# Diffinery > Diffinery is open-source code hosting and CI for the agentic era: Git repositories, pull requests with intent, GitHub Actions compatible workflows and AI agents as first-class collaborators, running on your own Cloudflare account. This file holds what Diffinery is and how it compares with other products (the home page, the product, comparison, FAQ and company pages), then the essential pages of the docs: Overview, Quickstart, Concepts, Guides, Move your GitHub Actions workflows to Diffinery, Make your CI faster on Diffinery, Give an AI coding agent its own account, with guardrails, Run Diffinery CI while your code stays on GitHub, Compatibility with GitHub Actions, Connect AI apps. Every docs page, including the API reference: https://diffinery.com/llms-full.txt. The index of everything: https://diffinery.com/llms.txt --- # Diffinery > Diffinery is open-source code hosting and CI for the agentic era, running on your own Cloudflare account: Git repositories, pull requests, GitHub Actions–compatible CI on 4-vCPU runners, and AI agents with their own accounts and guardrails. Source: https://diffinery.com/ (last updated 2026-10-25) ## Code hosting and CI for the agentic era Diffinery is an open-source GitHub alternative for teams of people and AI agents. Git repositories, pull requests, GitHub Actions–compatible CI on fast runners, and agents with their own accounts and guardrails, running entirely on your own Cloudflare account. - **4 vCPU**: per CI job by default. GitHub's standard runner for private repositories has 2. - **3–5 s**: from a job being queued to its first step. - **Apache-2.0**: Open source, with nothing to buy. You run it on your own Cloudflare account. - **1 person**: approves every agent pull request, enforced by the server. ## What you get - **[Git hosting](https://diffinery.com/features#git-hosting)**: Clone, fetch and push over HTTPS with Git LFS. Every repository is its own strongly consistent store, and pushes that leak a credential are refused. - **[Pull requests with intent](https://diffinery.com/features#pull-requests-reviews-and-issues)**: Reviews, required approvals and checks, auto-merge and a merge queue. Each pull request says what it's meant to do, so reviewers check the right thing. - **[GitHub Actions–compatible CI](https://diffinery.com/features#actions-ci-that-runs-your-github-workflows)**: The same triggers, expressions, matrices, reusable workflows, secrets, OIDC and Docker. Actions from GitHub run as they do there. - **[Fast, right-sized runners](https://diffinery.com/performance)**: 4 vCPUs and 12 GiB per job by default, started in seconds. Jobs that only wait move to smaller runners on their own, never at the cost of speed. - **[AI agents with guardrails](https://diffinery.com/agents)**: Agents get their own accounts and tokens, run tasks with Claude Code or Codex, review pull requests and merge on green. They can't push to protected branches or reach your secrets. - **[Secure by default](https://diffinery.com/security)**: Passkeys instead of passwords, invite-only sign-up, encrypted secrets, scoped job tokens and an append-only audit log. ## Built for AI coding agents Claude Code, Codex and other agents work through Git, the GitHub CLI, the REST API or the built-in MCP server, as accounts of their own, and Diffinery can run them for you. Every agent feature is opt-in, people bring their own model keys or subscriptions, and the server keeps a person in charge of what lands. - **[Agent accounts with guardrails](https://diffinery.com/docs/agents/overview#guardrails)**: Each agent has its own login and tokens, owned by a person or an organization. It can't push to protected branches, a person approves its pull requests, and runs of its code get no secrets. - **[Agent tasks](https://diffinery.com/docs/agents/tasks)**: Give an agent a goal: Claude Code or Codex works in a sandbox with your own model key and opens a pull request. Plan first, best of N attempts, and fixes for its own failing checks. - **[Agent review](https://diffinery.com/docs/agents/review)**: An agent reviews every pull request for bugs, security issues and logic errors, posts inline findings with suggested fixes and reports an Agent review check. - **[Today and Needs you](https://diffinery.com/docs/agents/today)**: One page each morning: what needs you, what your agents are working on, and what merged or failed since yesterday, across every repository. - **[Merge on green](https://diffinery.com/docs/collaboration/merge-on-green)**: Pull requests merge by themselves once their checks pass, with or without a person's approval, as you choose. An agent's change to a workflow file still needs a person to merge it. - **[Your own subscription](https://diffinery.com/docs/agents/terminal)**: Open a terminal in the browser, sign in to Claude Code or Codex with your own Claude or ChatGPT plan, and give it tasks that open pull requests. ## Works where you and your agents already work - **[Claude Code plugin](https://diffinery.com/docs/connect/claude-code)**: The MCP server, a skill for the branch → pull request → CI → merge loop, /diffinery:pr-status, and a live band of the pull request's CI checks above the prompt. `claude plugin marketplace add codician-team/diffinery` - **[Codex plugin](https://diffinery.com/docs/connect/codex)**: The same MCP server, skills and session hook for OpenAI's Codex CLI. `codex plugin marketplace add https://diffinery.com/codician/diffinery.git` - **[MCP server, in the official registry](https://diffinery.com/docs/agents/mcp)**: 52 tools for code, pull requests, CI logs, sandboxes, Today and the docs, with a browser sign-in, for Claude, Claude Code, Codex, Cursor and any MCP client. Listed as com.diffinery/diffinery. `https:///mcp` - **[The diffinery CLI and gh](https://diffinery.com/docs/agents/github-cli)**: Pull requests with intent, auto-merge, runs and logs, runners and migrations. gh works as it does with GitHub Enterprise, so agents use the commands they know. `curl -fsSL https://diffinery.com/install | bash` - **[VS Code, Cursor and Windsurf](https://diffinery.com/docs/repositories/clone-in-your-editor)**: Clone from Diffinery with a passkey sign-in, and push and pull with it. `https://diffinery.com/install-editor` - **[JetBrains IDEs](https://diffinery.com/docs/repositories/clone-in-jetbrains-ides)**: Get from Version Control with a passkey sign-in, in IntelliJ IDEA, PyCharm, WebStorm and the rest (2024.3 or later). `https://diffinery.com/-/jetbrains/updatePlugins.xml` ## Your workflows, as they are ```yaml name: CI on: [push, pull_request] jobs: test: runs-on: ubuntu-latest # 4 vCPU, 12 GiB on Diffinery steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: 22, cache: pnpm } - run: pnpm install --frozen-lockfile - run: pnpm test ``` ## How Diffinery compares | | Diffinery | GitHub | GitHub with a runner service | | --- | --- | --- | --- | | Git hosting, pull requests, issues | Yes | Yes | Yes, on GitHub | | Runs GitHub Actions workflows | Yes, as they are | Yes | Yes, with a new runs-on label | | Default Linux runner, private repositories | 4 vCPU, 12 GiB | 2 vCPU, 8 GB | Your choice of size, billed by the vendor | | Guardrails for AI agents | Built in for every agent account | Rulesets and permissions you configure | Rulesets and permissions you configure | | Built-in MCP server and agent sandboxes | Yes | MCP server, Codespaces | GitHub's | | Hosted macOS and Windows runners | No (self-hosted) | Yes | Depends on the vendor | | Open source | Yes, Apache-2.0 | No | No | | Who runs it | You, on your own Cloudflare account | GitHub | GitHub and the runner vendor | Runner services include Blacksmith and Depot. See [all comparisons](https://diffinery.com/compare). ## Open source, on your own Cloudflare account Diffinery is open source under the Apache License 2.0: [source code](https://diffinery.com/codician/diffinery), [mirror on GitHub](https://github.com/codician-team/diffinery). Deploy it with [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy); you pay Cloudflare only for what your instance uses. To try it first, [request early access](https://diffinery.com/early-access) to diffinery.com. See [Open source](https://diffinery.com/open-source). ## Frequently asked questions ### What is Diffinery? Diffinery is a git forge and CI platform for teams of people and AI agents. It hosts Git repositories, pull requests, issues and releases, runs GitHub Actions workflows on its own hosted runners, and gives AI agents their own accounts, tokens and server-enforced guardrails. It runs entirely on Cloudflare, and it's open source under the Apache License 2.0: you deploy it to your own Cloudflare account. ### Is Diffinery an alternative to GitHub? Yes, for teams whose work fits it: Diffinery replaces GitHub's code hosting, pull requests and GitHub Actions in one platform. It doesn't have GitHub's hosted macOS and Windows runners, forks, app marketplace, Codespaces, Pages or Discussions. See [Diffinery vs GitHub](https://diffinery.com/compare/github). ### Do my GitHub Actions workflows run on Diffinery? Most run without changes. Diffinery reads `.github/workflows/*.yml` with the same syntax, triggers, expressions and actions. Hosted runners are Linux x64; macOS, Windows and Arm jobs need a self-hosted runner. Every difference is listed in [Compatibility with GitHub Actions](https://diffinery.com/docs/actions/compatibility). ### Is Diffinery built on Cloudflare? Yes, entirely: Git hosting, pull requests with reviews in a web UI and GitHub Actions–compatible CI, marketplace actions included, all run on Cloudflare. One Cloudflare Worker serves the site, the API, Git and the MCP server; each repository is its own Durable Object, with large objects in R2 and accounts in D1; Workflows and Queues drive CI runs, webhooks and email; and every CI job runs in a Cloudflare Container that exists only while the job runs. There are no servers to manage. See [Built on Cloudflare](https://diffinery.com/built-on-cloudflare). ### How is Diffinery different from Blacksmith or Depot? Blacksmith sells faster runners for GitHub Actions, and Depot sells runners, its own CI engine and container builds. With either, your code and pull requests usually stay on GitHub and jobs run on their machines. Diffinery replaces GitHub and GitHub Actions together, with fast runners built in, as one open-source platform you run on your own Cloudflare account. See [Diffinery vs Blacksmith](https://diffinery.com/compare/blacksmith) and [Diffinery vs Depot](https://diffinery.com/compare/depot). ### How does Diffinery work with Claude Code, Codex and other AI agents? Agents connect over MCP at `/mcp` on your instance with a browser sign-in, or use Git, the GitHub CLI and the REST API with an agent token. Each agent is an account of its own: it can't push to protected branches, its pull requests need a person's approval, and runs of its code get no secrets. See [Diffinery for AI agents](https://diffinery.com/agents). ### How do I move from GitHub? Diffinery's importer copies a repository or a whole organization from GitHub on the server, with history, issues, pull requests, reviews, releases and branch protection, keeping their numbers. Then you enter your secrets' values and push. See [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github). ### Is Diffinery open source? Yes, under the Apache License 2.0, with no paid edition and nothing sold. The source code is at [diffinery.com/codician/diffinery](https://diffinery.com/codician/diffinery) and mirrored to [github.com/codician-team/diffinery](https://github.com/codician-team/diffinery). See [Open source](https://diffinery.com/open-source). ### Can I try Diffinery without deploying it? Yes. [Request early access](https://diffinery.com/early-access) to diffinery.com, the project's own instance: its administrators review requests and email invitations, and you try Diffinery there. To run Diffinery for your team, deploy your own instance. See [Early access](https://diffinery.com/docs/accounts/early-access). ### How do I start using Diffinery, and what does it cost? Deploy your own instance to your Cloudflare account and domain with one command, `scripts/setup.sh`, then sign in as its first administrator and invite your team. See [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy). Diffinery is free; you pay Cloudflare for what your instance uses, on the Workers Paid plan (a minimum of $5 USD per month per account, plus usage; [Cloudflare's pricing](https://developers.cloudflare.com/workers/platform/pricing/), checked October 25, 2026). There's no hosted service to sign up for; to try Diffinery first, [request early access](https://diffinery.com/early-access) to diffinery.com, the project's own instance. --- # Git hosting, pull requests and GitHub Actions–compatible CI in one place > Everything open-source Diffinery does: Git hosting, pull requests and a merge queue, GitHub Actions–compatible CI, a container registry and AI agents. Source: https://diffinery.com/features (last updated 2026-10-25) Diffinery is an open-source (Apache-2.0) git forge for teams of people and AI agents. It hosts your repositories, reviews and CI in one place, runs your existing GitHub Actions workflows as they are, and treats AI coding agents as accounts with their own tokens and guardrails. It runs entirely on Cloudflare: you [deploy your own instance](https://diffinery.com/docs/self-hosting/deploy) to your own Cloudflare account and domain, and there are no servers to manage. The source code is at [diffinery.com/codician/diffinery](https://diffinery.com/codician/diffinery), mirrored on [GitHub](https://github.com/codician-team/diffinery). This page lists what Diffinery does today, what it doesn't do yet, and where each feature is documented. ## Git hosting - **Clone, fetch and push over HTTPS** with a token or a browser sign-in from the CLI or your editor. Shallow clones, Git LFS, tags and `refs/pull//head` and `/merge` work as on GitHub. See [Git over HTTPS](https://diffinery.com/docs/repositories/git). - **Every repository is its own strongly consistent store.** Each repository is a Cloudflare Durable Object with its own SQLite database, so one busy repository never slows another. - **Push protection on by default.** Every push, and every commit made through the web editor, the API or MCP, is scanned for leaked credentials, and a push that contains one is refused with nothing kept. See [Push protection](https://diffinery.com/docs/security/push-protection). - **Branch protection** with required pull requests, approvals, required checks, linear history, merge queues and rules for agents. See [Branch protection](https://diffinery.com/docs/repositories/branch-protection). - **Browse code** in the web UI with highlighted files and diffs, history, branches and tags, a command palette and an in-browser editor. See [Browsing code](https://diffinery.com/docs/repositories/browsing-code). ## Pull requests, reviews and issues - **Pull requests with intent.** Every pull request can say what the change is meant to do, so human and AI reviewers check the right thing. Drafts, reviews with line comments, required approvals and checks, and merge, squash or rebase. See [Pull requests](https://diffinery.com/docs/collaboration/pull-requests). - **Auto-merge and a merge queue.** Pull requests land on their own once they're approved and green, and a merge queue tests each one on top of the base branch and the pull requests ahead of it, with the same `merge_group` event and `gh-readonly-queue/` branches as GitHub. See [Merge queue](https://diffinery.com/docs/collaboration/merge-queue). - **Issues** with labels, assignees, milestones, reactions, locking and search. See [Issues](https://diffinery.com/docs/collaboration/issues). - **Releases** with notes and downloadable files, following GitHub's model and REST API. See [Releases](https://diffinery.com/docs/collaboration/releases). - **Checks and commit statuses** from Diffinery Actions, external CI and bots. See [Checks and commit statuses](https://diffinery.com/docs/collaboration/checks-and-statuses). ## Actions: CI that runs your GitHub workflows - **Drop-in for GitHub Actions.** Diffinery reads `.github/workflows/*.yml` with the same triggers, expressions, matrices, `needs`, outputs, reusable workflows, environments, secrets, variables, OIDC, service containers and Docker. JavaScript, composite and Docker actions from GitHub run as they do there. See [Compatibility with GitHub Actions](https://diffinery.com/docs/actions/compatibility), which lists every difference. - **Fast built-in actions.** `actions/checkout`, `setup-node`, `setup-python`, `setup-go`, `cache`, `upload-artifact` and `download-artifact` are built into the runner, sharing storage and formats with the official actions. Caches restore in parallel ranges while they extract. - **Hosted runners on Cloudflare Containers.** Each job gets a fresh Ubuntu 24.04 x64 container with 4 vCPUs and 12 GiB of memory by default. Jobs start in about 3 to 5 seconds. See [Runners](https://diffinery.com/docs/actions/runners) and the [measured performance](https://diffinery.com/performance). - **Right-sized automatically.** Four sizes, from 1/4 vCPU to 4 vCPUs. Diffinery measures what each job uses and moves a job to a smaller runner only when its own runs show it fits with room to spare on the slowest hosts, and moves it back if it ever runs slower. See [Runner sizes](https://diffinery.com/docs/actions/runners#runner-sizes). - **Self-hosted runners** for macOS, Windows, Arm, GPUs or machines on your own network, with `diffinery runner`. See [Self-hosted runners](https://diffinery.com/docs/actions/runners#self-hosted-runners). - **Caches and artifacts** with the official `actions/cache` and `upload-artifact` formats. See [Caching and artifacts](https://diffinery.com/docs/actions/caching-and-artifacts). ## Container registry Push and pull images at `//` (such as `diffinery.com//` on diffinery.com) with `docker`, `podman`, `buildx`, `crane` or the `docker/*` actions, instead of ghcr.io. Images are private by default and can be linked to a repository whose collaborators then share access. See [Container registry](https://diffinery.com/docs/packages/container-registry). ## Built for AI agents - **Agents are accounts.** Each AI agent gets its own login and tokens, acts for a person or an organization, and is held to guardrails: unless a branch protection rule allows it, an agent can't push to or merge into protected branches, its pull requests need a person's approval, its check results never count as required checks, and runs of code it pushed get no secrets. See [Guardrails](https://diffinery.com/docs/agents/overview#guardrails). - **Agent tasks.** Give an agent a goal and get a pull request back: Claude Code, Codex or your own command works in a sandbox with your own model key, which never enters the sandbox. Tasks can plan first, run up to four attempts side by side, and fix their own failing checks. See [Agent tasks](https://diffinery.com/docs/agents/tasks). - **Agent review.** An agent reviews pull requests for bugs, security issues and logic errors, posts inline findings with suggested fixes, and reports an Agent review check; **Fix it** and autofix hand a finding to an agent task. See [Agent review](https://diffinery.com/docs/agents/review). - **Today and Needs you.** One page, the first after you sign in, with what needs you, what your agents are working on and what merged or failed since yesterday, also as a morning email and the `today` MCP tool. See [Today](https://diffinery.com/docs/agents/today). - **Merge on green.** Pull requests, agents' included, merge by themselves once their checks pass and their branch's rules are met. See [Merge on green](https://diffinery.com/docs/collaboration/merge-on-green). - **Terminals on your own subscription.** A shell in your browser with the repository checked out, where Claude Code or Codex runs on your own Claude or ChatGPT plan and can take tasks. See [Terminals](https://diffinery.com/docs/agents/terminal). - **Projects, sandboxes and an MCP server.** A board of each repository's agent tasks with shared memory and an optional coordinator, short-lived sandboxes to build and test in, and an MCP server at `/mcp` (`https://diffinery.com/mcp` on diffinery.com), listed in the official MCP Registry as `com.diffinery/diffinery`. ![The Today page on Diffinery: what needs you, the agent pull requests at work, your agent tasks and what changed since yesterday](https://diffinery.com/docs/images/today.webp) See [Diffinery for AI agents](https://diffinery.com/agents) for the whole picture. ## Works with the tools you already use | Tool | How it works with Diffinery | | --- | --- | | `git` | Standard Git over HTTPS. `diffinery auth setup-git` signs git in through the browser. | | GitHub CLI (`gh`) | Works as with GitHub Enterprise Server, through Diffinery's GitHub-compatible REST and GraphQL APIs. See [Use gh](https://diffinery.com/docs/agents/github-cli). | | VS Code, Cursor, Windsurf | "Clone from Diffinery" with a passkey sign-in. See [Clone in your editor](https://diffinery.com/docs/repositories/clone-in-your-editor). | | JetBrains IDEs | Get from Version Control with a passkey sign-in. See [Clone in JetBrains IDEs](https://diffinery.com/docs/repositories/clone-in-jetbrains-ides). | | Claude Code | The `diffinery` plugin (the MCP server, a skill, `/diffinery:pr-status` and a session hook) and the `diffinery-ci` plugin (a live band of the pull request's CI checks above the prompt). `claude plugin marketplace add codician-team/diffinery`. See [Claude Code](https://diffinery.com/docs/connect/claude-code) and [CI status in Claude](https://diffinery.com/docs/connect/ci-status-in-claude). | | Codex | The `diffinery` plugin with the MCP server, skills and a session hook. See [Codex](https://diffinery.com/docs/connect/codex). | | Claude, Cursor and other MCP clients | The MCP server at `/mcp` with a browser sign-in, listed in the [official MCP Registry](https://registry.modelcontextprotocol.io/v0/servers?search=com.diffinery/diffinery) as `com.diffinery/diffinery`. See [Connect AI apps](https://diffinery.com/docs/connect). | | Scripts and integrations | A GitHub-style REST API at `/api/v3`, described as [OpenAPI 3.1](https://diffinery.com/docs/api/openapi.json), and GitHub-compatible [webhooks](https://diffinery.com/docs/repositories/webhooks). | | The `diffinery` CLI | Repositories, pull requests, issues, runs, secrets, runners and migrations from a terminal. See the [CLI reference](https://diffinery.com/docs/reference/cli). | ## Moving from GitHub A server-side importer brings over a GitHub repository, or every repository of an organization, with its full Git history, issues, pull requests, reviews, comments, labels, milestones, releases and branch protection, keeping issue and pull request numbers. Secret names come across with a field to enter each value. Start it from the web, the CLI (`diffinery migrate github`), the REST API or MCP; nothing runs on your machine. See [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github). ## Security Passkeys instead of passwords, invite-only sign-up by default, branch and push protection, envelope-encrypted secrets, job tokens limited by `permissions:`, signed webhooks and an append-only audit log. See [Security](https://diffinery.com/security). ## How it runs Everything runs on Cloudflare, in the account you deploy your instance to: a Worker serves the web UI, Git, the REST API and MCP; each repository is a Durable Object with SQLite; large objects, caches, artifacts and images live in R2; accounts live in D1; workflow runs are durable Cloudflare Workflows; and jobs and agent sandboxes run in Cloudflare Containers. See [Architecture](https://diffinery.com/docs/self-hosting/architecture). Diffinery itself is free. You pay Cloudflare for what your instance uses: it needs the Workers Paid plan, plus usage above the included amounts. See [Built on Cloudflare](https://diffinery.com/built-on-cloudflare#run-diffinery-on-your-own-cloudflare-account). ## What Diffinery doesn't do yet Diffinery is young, and we'd rather you know its limits before you move: - **Hosted runners are Linux x64 only.** macOS, Windows and Arm jobs need [self-hosted runners](https://diffinery.com/docs/actions/runners#self-hosted-runners). - **HTTPS only for Git.** There's no SSH access. - **No forks.** Pull requests are between branches of the same repository. - **No wikis, discussions, GitHub Pages-style sites, Codespaces-style cloud editors or app marketplace.** - **Reviews are simpler than GitHub's.** No pending reviews, suggested changes or thread resolution yet, and branch protection has no code-owner reviews or signed-commit requirement. - **No hosted service.** Nobody runs Diffinery for you: you deploy and run your own instance in your own Cloudflare account, and you pay Cloudflare for what it uses. See [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy). --- # Open source > Diffinery is free, open-source software (Apache-2.0). Get the source, deploy it to your own Cloudflare account, see what it costs, and contribute. Source: https://diffinery.com/open-source (last updated 2026-10-25) Diffinery is open source under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). Everything on this site, from Git hosting and pull requests to GitHub Actions–compatible CI, hosted runners, the MCP server and the agent features, is in one public repository. There are no plans, prices or sales, and no paid edition. You run Diffinery yourself, on your own Cloudflare account and domain. ## Source code | | | | --- | --- | | Repository | [diffinery.com/codician/diffinery](https://diffinery.com/codician/diffinery), where Diffinery is developed and its CI runs | | Mirror on GitHub | [github.com/codician-team/diffinery](https://github.com/codician-team/diffinery) | | License | Apache-2.0, in the repository's `LICENSE` file, with a `NOTICE` file ("Copyright 2026 The Diffinery Authors") | | Language and platform | TypeScript, on Cloudflare Workers, Durable Objects, R2, D1, Queues, Workflows and Containers. See [Architecture](https://diffinery.com/docs/self-hosting/architecture). | Clone it from either place: ```bash git clone https://diffinery.com/codician/diffinery.git # or git clone https://github.com/codician-team/diffinery.git ``` The Apache License lets you use, change and redistribute Diffinery, commercially or not, as long as you keep the license and notices; it also grants a patent license from contributors. Read the [license text](https://www.apache.org/licenses/LICENSE-2.0) for the exact terms. ## Run your own Diffinery Diffinery is one Cloudflare Worker plus the Cloudflare products it binds to, so an instance has no servers, virtual machines or databases of its own. One command, `scripts/setup.sh` from a clone, checks your tools, API token and zone and then deploys: it creates what's missing in your Cloudflare account (the D1 database, R2 bucket, queues, Turnstile widget and Cloudflare Access application), applies migrations, uploads the Worker and builds the runner image. Then you sign in as the first administrator and invite your team. What you need: - A Cloudflare account on the Workers Paid plan, with R2 turned on. - A domain added to that account, for your instance's hostname. - A Cloudflare Zero Trust organization, for the first administrator's email sign-in and passkey recovery. - A machine with Node.js 22, pnpm, `jq`, `curl`, `openssl` and Docker to run the deploy, or a forge with GitHub-compatible Actions to run the Deploy workflow. Nobody who uses your instance needs a Cloudflare account; only the deployment does. Follow [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy) step by step, and see [Self-hosting](https://diffinery.com/docs/self-hosting) for an overview and [Configuration](https://diffinery.com/docs/self-hosting/configuration) for every setting. ## What it costs Diffinery is free. You pay Cloudflare for what your instance uses, on your own Cloudflare bill: - The Workers Paid plan has "a minimum cost of $5 USD per month per account", which includes Workers and Durable Objects usage up to its allowances, and you pay for usage above them ([Workers pricing](https://developers.cloudflare.com/workers/platform/pricing/), checked October 25, 2026). - Hosted CI runners and agent sandboxes are Cloudflare Containers. Cloudflare bills a container by the 10 ms while it runs ([Containers pricing](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026), and Diffinery starts one only when a job starts and stops it when the job ends, so idle time costs nothing. Jobs that mostly wait move to smaller runners on their own ([Runner sizes](https://diffinery.com/docs/actions/runners#runner-sizes)). - R2, D1, Queues and Workflows bill by use under Cloudflare's own pricing for each product. What a month costs depends on how much your team pushes and builds. Each instance sets per-account quotas for hosted minutes, jobs at once, sandboxes, repositories and storage, with defaults its administrators change; see [Limits](https://diffinery.com/docs/reference/limits#account-quotas). ## What diffinery.com is diffinery.com is the project's home: this site, the [documentation](https://diffinery.com/docs), and the Diffinery instance that Diffinery itself is developed on, with its CI, deploys and agents. Accounts there are by invitation. If you'd like to try Diffinery before running your own, [request early access](https://diffinery.com/early-access): its administrators review requests and email invitations. It isn't a hosted service for teams; to use Diffinery for your work, run your own instance. ## Contribute - **Issues and pull requests:** on [the GitHub mirror](https://github.com/codician-team/diffinery) if you don't have a diffinery.com account, or on [the Diffinery repository](https://diffinery.com/codician/diffinery). The repository's `CONTRIBUTING.md` explains how to build, test and send changes. - **Security problems:** report them privately with the [report form](https://diffinery.com/security/report), not in a public issue. See [Vulnerability disclosure](https://diffinery.com/docs/security/disclosure). - **Docs:** every page at [/docs](https://diffinery.com/docs) is Markdown in the repository, under `apps/diffinery/docs/`. ## Frequently asked questions ### Is Diffinery open source? Yes, under the Apache License 2.0. The source is at [diffinery.com/codician/diffinery](https://diffinery.com/codician/diffinery) and mirrored to [github.com/codician-team/diffinery](https://github.com/codician-team/diffinery). ### Is there a paid or enterprise edition? No. There's one edition, the open-source one, and nothing is sold. ### Is there a hosted version I can sign up for? Not one to sign up for. To try Diffinery, [request early access](https://diffinery.com/early-access) to diffinery.com, the project's own instance, where accounts are by invitation. To use Diffinery for your team, deploy your own instance to your Cloudflare account; see [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy). ### What does running Diffinery cost? Diffinery itself is free. Your instance runs on your Cloudflare account, which needs the Workers Paid plan (a minimum of $5 USD per month per account, plus usage above its allowances), and pays for containers, storage and the other Cloudflare products by use. See [What it costs](https://diffinery.com/open-source#what-it-costs). ### Can I run Diffinery somewhere other than Cloudflare? No. Diffinery is built on Cloudflare's products (Workers, Durable Objects, R2, D1, Queues, Workflows and Containers) and has no version for other clouds or for your own servers. Self-hosted runners, though, run jobs on any machine you control; see [Self-hosted runners](https://diffinery.com/docs/actions/runners#self-hosted-runners). --- # Git hosting and CI built for AI coding agents > AI agents get accounts with guardrails, tasks with Claude Code or Codex, agent review, Today, merge on green and plugins. People decide what lands. Source: https://diffinery.com/agents (last updated 2026-10-25) Coding agents such as Claude Code and Codex now write a large share of many teams' pull requests. Diffinery is an open-source git forge designed for that, which you run on your own Cloudflare account ([Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy)): agents work through the same Git, REST API and CI as people, but as accounts of their own, with limits the server enforces, so a person stays in charge of what reaches your main branch. Diffinery can also run your agents for you. Give one a goal and Claude Code or Codex opens a pull request from a sandbox; have another review every pull request; open **Today** in the morning to see what needs you; approve, and let it merge on green. Plugins for Claude Code and Codex, an MCP server in the official MCP Registry, the `diffinery` CLI, `gh` and editor extensions bring it into the tools you already use. | What | In one line | | --- | --- | | [Agent accounts](https://diffinery.com/agents#agents-are-accounts-not-borrowed-tokens) | Their own logins and tokens, owned by a person or an organization | | [Guardrails](https://diffinery.com/agents#guardrails-the-server-enforces) | No pushes to protected branches, a person approves, no secrets for agent code | | [Agent tasks](https://diffinery.com/agents#agent-tasks-a-goal-in-a-pull-request-out) | A goal in, a pull request out, with Claude Code or Codex in a sandbox | | [Agent review](https://diffinery.com/agents#agent-review-on-every-pull-request) | Inline findings and an Agent review check on every pull request | | [Today and Needs you](https://diffinery.com/agents#today-what-needs-you) | What needs you and what your agents did since yesterday | | [Merge on green](https://diffinery.com/agents#merge-on-green) | Agent pull requests land when their checks pass, after a person approves if you want that | | [Plugins and integrations](https://diffinery.com/agents#plugins-and-integrations) | Claude Code, Codex, MCP, the CLI, gh, VS Code and JetBrains | ## Agents are accounts, not borrowed tokens On most forges an agent acts with a person's token, so its work is indistinguishable from theirs and it can do anything they can. On Diffinery: - **Each agent has its own login and tokens**, owned by a person or an organization. Every commit it makes is stamped with who it acts for. - **Its role is capped** by a maximum role (write by default) and by its owner's own role. - **It can't sign in to the web UI.** Agents use tokens over Git, the REST API, the CLI and MCP; only people have passkeys and browser sessions. See [Agents](https://diffinery.com/docs/agents/overview). ## Guardrails the server enforces These hold for Git pushes, the REST API, MCP tools and sandboxes alike: | Rule | What it means | | --- | --- | | No pushes to protected branches | Agents open pull requests instead. A branch protection rule can allow it. | | A person approves agent pull requests | At least one approval from a person, even on a branch with no rule. An agent's approval never counts. | | No merging protected branches | Unless a rule allows agents to merge, or to land through auto-merge once CI and a person agree. | | Agent check results never satisfy required checks | An agent can't report its own CI as green. | | No secrets for agent code | A workflow run of code an agent pushed gets only its job token, so an agent can't push a workflow that sends your secrets elsewhere. | | No secret, variable, environment or branch protection changes | Whatever the agent's role. | | No push protection bypass | A credential in an agent's push is always refused. | The full list is in [Guardrails](https://diffinery.com/docs/agents/overview#guardrails). ## An MCP server for every AI app Every Diffinery instance runs a Model Context Protocol server at `/mcp` on its domain (`https://diffinery.com/mcp` on diffinery.com). Claude (claude.ai, Desktop and mobile), Claude Code, Codex, Cursor, VS Code and other MCP clients sign in through the browser with OAuth 2.1, or headless with an agent token. Its tools read code, commit files, open, review and merge pull requests, follow CI and read job logs, publish releases, import from GitHub, run commands in sandboxes and search these docs, all through the same permission checks and guardrails as Git and the REST API. - [Connect AI apps](https://diffinery.com/docs/connect): one URL and a browser sign-in for Claude, Claude Code, Codex and others. - [MCP tool reference](https://diffinery.com/docs/reference/mcp-tools): every tool and its arguments, generated from the server. - Listed in the [official MCP Registry](https://registry.modelcontextprotocol.io/v0/servers?search=com.diffinery/diffinery) as `com.diffinery/diffinery`, for anyone's own instance. - Plugins for Claude Code and Codex add the MCP server, skills and a session hook in one install: see [Plugins and integrations](https://diffinery.com/agents#plugins-and-integrations). ## gh, Git and the REST API work as agents expect Agents trained on GitHub already know how to use Diffinery. The GitHub CLI works with Diffinery as it does with GitHub Enterprise Server (`diffinery auth setup-gh` signs it in), so `gh pr create`, `gh pr checks` and `gh pr merge` just work, and Claude Code shows the pull request and CI status of the branch it's on. The REST API follows GitHub's at `/api/v3`, with a GraphQL endpoint for the queries `gh` makes. See [Use gh with Diffinery](https://diffinery.com/docs/agents/github-cli). ## Sandboxes: a machine for every agent A [sandbox](https://diffinery.com/docs/agents/sandboxes) is a short-lived Linux container with the repository already cloned, driven over MCP or the REST API: run commands, read and write files, build, test and push. An agent working from a chat app gets a real machine without anyone setting one up. ## Agent tasks: a goal in, a pull request out Give one of your agents a goal. Diffinery starts a sandbox as that agent with the repository checked out, runs Claude Code, Codex or your own command with your own model key, streams its transcript to the task page, then pushes a branch and opens a pull request for a person to review. Your API key never enters the sandbox: each run gets a token that only Diffinery's model proxy accepts. A task can **plan first** and wait for your approval, run up to four **attempts** side by side for you to pick from, and **verify and land**: start a fix run when its checks fail, and merge once a person approves. ![An agent task on Diffinery: the goal, Claude Code running as the acme-coder agent, its transcript with file edits and test runs, and the pull request it opened](https://diffinery.com/docs/images/agent-task.webp) To use your own **Claude or ChatGPT subscription** instead of an API key, open a [terminal](https://diffinery.com/docs/agents/terminal): a shell in your browser with the repository checked out, where Claude Code or Codex runs on your own plan, and which can take tasks too. See [Agent tasks](https://diffinery.com/docs/agents/tasks). ## Agent review on every pull request One of your agents reviews pull requests for bugs, security issues and logic errors, the way Cursor's Bugbot does. It runs in a read-only sandbox with the base branch's `REVIEW.md` rules, posts its findings as inline comments with suggested fixes, and reports an **Agent review** check that fails when a finding is blocking. **Fix it** under a finding starts an agent task on the pull request's branch, and autofix does it for every finding. See [Agent review](https://diffinery.com/docs/agents/review). ![A pull request opened by an agent on Diffinery, with its intent, the task that wrote it, and an agent review with an inline finding, a suggested fix and a Fix it button](https://diffinery.com/docs/images/agent-pull-request.webp) ## Today: what needs you [Today](https://diffinery.com/docs/agents/today) is the first page after you sign in: what needs you (agent pull requests waiting for a person, reviews you were asked for, your own blocked pull requests), what your agents are working on, your agent tasks, and what merged, shipped or failed since yesterday, across every repository you can see. Agents read the same view with the `today` MCP tool, and it can come by email each morning. ![The Today page on Diffinery: counts of what needs you, agent pull requests and failed runs, then the Needs you, Agents at work, Your agent tasks and Since yesterday sections](https://diffinery.com/docs/images/today.webp) ## Merge on green In **Settings → Merge on green**, a repository admin picks the checks that must pass and the agents whose pull requests land by themselves, and chooses whether a person's approval is still needed. Then pull requests merge the moment their checks pass and their branch's rules are met, with nobody clicking Merge. An agent's change to a workflow file still needs a person to merge it. See [Merge on green automatically](https://diffinery.com/docs/collaboration/merge-on-green). ![The merge box of an agent's pull request on Diffinery: its required check passed and auto-merge is on, waiting for a person's approval](https://diffinery.com/docs/images/merge-on-green.webp) ## Projects with shared memory Every repository is also a [project](https://diffinery.com/docs/agents/projects): a board of its agent tasks, a conversation for the people working on it, instructions every task follows and a memory every task reads. Each person can turn on a coordinator, an agent that turns their posts into tasks within the limits admins set. Every agent feature is optional and off until someone turns it on. People bring their own model keys or subscriptions; Diffinery doesn't sell or include model access. ## Plugins and integrations | Tool | What it adds | How to get it | | --- | --- | --- | | Claude Code | The `diffinery` plugin: the MCP server, a skill for the branch → pull request → CI → merge loop, `/diffinery:pr-status` and a session hook. The `diffinery-ci` plugin: a live band of the pull request's checks above the prompt and a note to Claude when CI settles. | `claude plugin marketplace add codician-team/diffinery`, then `claude plugin install diffinery@diffinery` and `diffinery-ci@diffinery`. See [Claude Code](https://diffinery.com/docs/connect/claude-code). | | Codex | The same MCP server, skills and session hook. | `codex plugin marketplace add https://diffinery.com/codician/diffinery.git`, then `codex plugin add diffinery@diffinery`. See [Codex](https://diffinery.com/docs/connect/codex). | | Any MCP client | The MCP server, listed in the [official MCP Registry](https://registry.modelcontextprotocol.io/v0/servers?search=com.diffinery/diffinery) as `com.diffinery/diffinery` (checked October 25, 2026). | `https:///mcp`. See [MCP](https://diffinery.com/docs/agents/mcp). | | Claude (claude.ai, Desktop, mobile) | Diffinery as a custom connector. | Settings → Connectors → Add custom connector. See [Claude](https://diffinery.com/docs/connect/claude). | | Terminal | The `diffinery` CLI: pull requests with intent, auto-merge, runs and logs. `diffinery setup` signs in and sets up git, gh and both Claude Code plugins. | `curl -fsSL https://diffinery.com/install \| bash`. See [CLI sign-in](https://diffinery.com/docs/accounts/cli-sign-in). | | GitHub CLI | `gh pr create`, `gh pr checks`, `gh pr merge` and the rest. | `diffinery auth setup-gh`. See [Use gh](https://diffinery.com/docs/agents/github-cli). | | VS Code, Cursor, Windsurf | Clone from Diffinery with a passkey sign-in. | [Clone in your editor](https://diffinery.com/docs/repositories/clone-in-your-editor). | | JetBrains IDEs | Get from Version Control with a passkey sign-in. | [Clone in JetBrains IDEs](https://diffinery.com/docs/repositories/clone-in-jetbrains-ides). | ## Docs written for agents to read Every docs page is available as Markdown (add `.md` to its URL, or send `Accept: text/markdown`). [/llms.txt](https://diffinery.com/llms.txt) indexes the site and the docs, [/llms-full.txt](https://diffinery.com/llms-full.txt) holds all of it in one file, the REST API is described as [OpenAPI 3.1](https://diffinery.com/docs/api/openapi.json), and agents connected over MCP can call `search_docs` and `read_docs`. See [Docs for AI agents](https://diffinery.com/docs/agents/docs-for-agents). ## Frequently asked questions ### Which AI coding agents work with Diffinery? Any agent that uses Git, the GitHub CLI, a REST API or MCP. There are step-by-step guides for Claude, Claude Code, Codex, Cursor and VS Code, plugins for Claude Code and Codex, and agent tasks and agent review run Claude Code or Codex for you. ### Can I use my Claude or ChatGPT subscription? In a [terminal](https://diffinery.com/docs/agents/terminal), yes: you sign in to Claude Code or Codex there with your own plan, and can give it tasks that open pull requests. Headless agent tasks and agent review use an API key (Anthropic, OpenAI or OpenRouter), because the providers allow automated use with API keys. Codex on a ChatGPT plan is offered on private repositories only. ### Can an agent merge its own pull request? Not by default. A person has to approve an agent's pull request, and agents can't merge into the default branch or protected branches. A repository admin can let agents land approved pull requests through auto-merge, so CI and a person decide rather than the agent. ### Do I need to give Diffinery my model API key? Only to run agent tasks or agent review with an API key. The key is stored encrypted and never enters the sandbox; runs reach the model through Diffinery's proxy with a token scoped to that run. Terminals use your own Claude or ChatGPT sign-in instead, and nothing else needs a key. ### Is Diffinery only for agents? No. People use the same web UI, Git, pull requests and CI as on any forge. Agents are first-class collaborators alongside them. --- # How fast Diffinery Actions runs, measured > Measured job start, checkout, cache, install, Docker and toolchain times on Diffinery's hosted runners, next to GitHub's published runner specs. Source: https://diffinery.com/performance (last updated 2026-10-25) We measured every stage of typical CI jobs on Diffinery's live hosted runners on October 16, 2026, and set them next to GitHub's published runner specifications. Nothing was run on GitHub for this page: GitHub's figures are its own published specs and documentation, linked below. Our numbers are ranges from repeated runs, because Cloudflare places containers on hosts of different speeds. ## Summary - **CPU-heavy jobs are faster.** A Diffinery job gets 4 vCPUs and 12 GiB of memory by default. GitHub's standard Linux runner for private repositories has 2 vCPUs and 8 GB, so builds and test suites that use several cores finish up to about twice as fast. For public repositories GitHub's standard runner also has 4 vCPUs, so there it's about even. - **Jobs start in seconds.** About 3 to 5 seconds from a job being queued to its first step, and 6 to 8 seconds from a push to the first job running. - **Setup steps are at or near parity.** Checkout takes 1 to 3 seconds, restoring a 216 MB pnpm cache 3 to 4 seconds on fast hosts, and `pnpm install` from that cache 3 to 7 seconds. - **Where GitHub is still a little faster:** GitHub's image preinstalls Go, Java and a running Docker daemon. Here `setup-go` takes 1 to 3 seconds and `setup-java` 2 to 5 seconds against about a second there, and the first `docker` command waits 0 to 2 seconds for the daemon. ## Machine | | Diffinery (default, large) | GitHub standard runner, private repository | GitHub standard runner, public repository | | --- | --- | --- | --- | | vCPU | 4 | 2 | 4 | | Memory | 12 GiB | 8 GB | 16 GB | | Disk | 20 GB | 14 GB SSD | 14 GB SSD | | Architecture | x64 | x64 (arm64 available) | x64 (arm64 available) | | Smaller sizes | 2, 1/2 and 1/4 vCPU, chosen per job from its own measured runs | 1 vCPU `ubuntu-slim` (15-minute job limit) | Same | GitHub's figures are from [GitHub-hosted runners reference](https://docs.github.com/en/actions/reference/runners/github-hosted-runners), checked October 16, 2026. GitHub sells 4-core and larger Linux runners for private repositories on its Team and Enterprise plans, at twice the per-minute price of the 2-core runner ([runner pricing](https://docs.github.com/en/billing/reference/actions-runner-pricing)). ## Stage by stage: a typical Node.js CI job Measured on Diffinery's large runner (4 vCPU) with the jobs of Diffinery's own CI and benchmark workflows: | Stage | Diffinery | Notes | | --- | --- | --- | | Push to first job running | 6 to 8 s | From `git push` returning to the first job's first step. | | Job start | About 3 to 5 s | A fresh container per job. | | `actions/checkout` | 1 to 3 s | Built into the runner. | | Restore a 216 MB pnpm cache | 3 to 4 s on fast hosts, about 10 s on the slowest | Downloads 16 ranges at once and extracts while it downloads. The whole `setup-node` step takes 5 to 10 s. | | `pnpm install` from that cache | 3 to 7 s | | | Upload a 200 MB artifact | 7 to 9 s | Blocks uploaded in parallel and joined as parallel parts. | | `setup-python`, `setup-node` | 0 s and 2 s | Python 3.12 and Node.js 22 are preinstalled. | | `setup-go`, `setup-java` (Temurin) | 1 to 3 s and 2 to 5 s | Installed while checkout runs, checked against the published SHA-256. GitHub preinstalls them, about 1 s. | | First `docker` command after checkout | 0.03 to 0.3 s | The daemon starts as the job begins, only for jobs that use Docker. | | First `docker` command as a job's very first step | 1.4 to 2.3 s | GitHub's daemon is already running: 0 s. | ## The same small job on every runner size A lint job: checkout, `npm ci` (89 packages), eslint, prettier and `tsc` on 40 files, two runs per size. | Size | vCPU | Whole job | `tsc` step | | --- | --- | --- | --- | | tiny | 1/4 | 15 to 27 s | 7 to 14 s | | small | 1/2 | 13 to 14 s | 5 s | | medium | 2 | 10 to 13 s | 2 to 3 s | | large | 4 | 9 to 14 s | 2 to 4 s | A job that only makes API calls (ten REST requests) took 4 seconds on both tiny and large. That's why Diffinery sizes each job from what its own runs used: jobs that wait can run on a small machine at no cost in speed, and jobs that compute keep the large one. A job moves to a smaller size only when every one of its recent runs fits there with room to spare on the slowest hosts, and goes back to large for its next 20 runs if a smaller size ever makes it slower. See [Runner sizes](https://diffinery.com/docs/actions/runners#runner-sizes). ## A real pipeline: Diffinery's own pull requests Diffinery is developed on Diffinery. Every pull request runs 10 required checks: a typecheck and bundle, two unit test shards and seven end-to-end suites that start a real Diffinery server and drive Git, pull requests, Actions, passkeys, agents, Docker and large pushes against it. From the first job starting to the last job finishing, the checks take about 3 minutes, and up to about 6 minutes when the jobs land on the slowest hosts. ## Why it's fast - **4 vCPUs by default**, so parallel test runners, bundlers and compilers have room. - **The common actions are built into the runner.** `checkout`, `setup-node`, `setup-python`, `setup-go`, `cache` and the artifact actions run natively instead of being downloaded and started in Node.js for every job. - **Head starts.** The runner reads the workflow before the first step and starts Docker, Go or a JDK while checkout runs, only for jobs that use them. - **Parallel transfers.** Caches download in 16 ranges at once and extract as they arrive; artifacts upload in parallel parts. - **A fresh machine per job.** A container exists only while its job runs, so jobs never wait behind another job's leftovers or share a dirty workspace. ## What isn't faster yet - **Toolchains GitHub preinstalls.** Go, Java, Ruby, Rust, .NET and browsers are installed per job here. Go and Java get a head start; others install as the step runs. Shipping them all in the image would make it bigger for every job and slower to roll out to new hosts, so the image stays small on purpose. - **Slow hosts.** Cloudflare's hosts span three AMD EPYC generations about 2x apart per core, and we don't choose which one a job lands on. The ranges above include them. - **Linux x64 only.** There are no hosted macOS, Windows or Arm runners; use [self-hosted runners](https://diffinery.com/docs/actions/runners#self-hosted-runners) for those. ## How we measured - All Diffinery numbers come from runs on the production hosted runners of diffinery.com, the instance Diffinery is developed on, on October 16, 2026, after the changes that produced them were deployed. Benchmark workflows ran on a separate scratch repository, not on Diffinery's own CI. - Stage times are from step timestamps in job logs. Upload times were measured by timing the upload and join calls separately. Each benchmark ran at least twice per configuration, Docker, Go and Java three times before and after each change. - GitHub's specs and prices are from GitHub's documentation, read on October 16, 2026. We did not run benchmarks on GitHub. - Results depend on your workflow. If you run your own Diffinery instance ([Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy)) with your own workflows, every job's log ends with what it used (busy cores, peak memory and disk) and names the runner size it got. See also: [Diffinery vs GitHub](https://diffinery.com/compare/github) and [Runners](https://diffinery.com/docs/actions/runners). --- # Security built in, not bolted on > How Diffinery protects code and secrets: passkeys instead of passwords, push protection, encrypted secrets, scoped job tokens, agent guardrails, audit log. Source: https://diffinery.com/security (last updated 2026-10-25) A forge holds a team's most valuable asset and the keys to its production systems. When AI agents push code and run workflows too, the forge has to enforce limits on its own, not trust that every token is used well. These are the protections every account and repository on a Diffinery instance gets by default. Diffinery is open source (Apache-2.0), so you can read the code that enforces them at [diffinery.com/codician/diffinery](https://diffinery.com/codician/diffinery). ## People sign in with passkeys There are no passwords to guess, reuse or phish. People sign in with a passkey (WebAuthn) kept by their device, password manager or security key, with user verification required. Passkeys are bound to your instance's domain (`diffinery.com` on diffinery.com), so a look-alike site can't use them. Sensitive actions, such as creating an agent or a token, ask you to confirm with your passkey again when your sign-in is older than two hours. See [Passkeys and sign-in](https://diffinery.com/docs/accounts/passkeys-and-sign-in). ## Invite-only by default Every Diffinery instance is invite-only by default: nobody joins without an invitation from a site administrator, an organization owner or admin, or a repository admin. Invite links work once and expire after 14 days. An instance's administrators can open sign-up with `SIGNUP=open` ([Configuration](https://diffinery.com/docs/self-hosting/configuration#signup)). See [Invitations](https://diffinery.com/docs/accounts/invitations). ## Leaked credentials never land Every push, and every commit made through the web editor, the REST API or MCP, is scanned for credentials such as cloud keys and tokens. A push that contains one is refused, and nothing from it is kept. Only a repository admin who is a person can push past it, with an audited reason; an agent never can. See [Push protection](https://diffinery.com/docs/security/push-protection). ## Secrets stay secret - **Envelope encryption** with a key per repository, environment or organization, derived from a master key that can be rotated. - **Masked in logs:** secret values are replaced with `***`. - **Never handed to agent code:** a workflow run of code an agent pushed gets no repository or organization secrets, so an agent can't push a workflow that sends them elsewhere. - **Job tokens** valid for one job and limited by the workflow's `permissions:`, read-only by default for new repositories, plus short-lived OIDC id tokens so deploys need no long-lived cloud keys. See [OIDC](https://diffinery.com/docs/actions/oidc). ## A human in the loop for agents AI agents are accounts with their own tokens and server-enforced guardrails: no pushes to protected branches, a person's approval on every agent pull request, agent check results never counted as required checks, and no secret, variable, environment or branch protection changes. See [Diffinery for AI agents](https://diffinery.com/agents) and [Guardrails](https://diffinery.com/docs/agents/overview#guardrails). ## Tokens with limits Personal and agent tokens (`dfy_...`) are stored hashed, expire, and can be limited to read, write or admin scope and to specific repositories. A read token never writes. See [Personal access tokens](https://diffinery.com/docs/accounts/tokens). ## Every sensitive action is recorded An append-only audit log records sign-ins, token and agent changes, permission changes, secret changes, push protection bypasses and more, and security emails tell you when something important changes on your account. See [Audit log](https://diffinery.com/docs/security/audit-log). ## Isolation Each repository is its own Durable Object with its own database, each workflow job runs in a fresh container thrown away after the job, and each agent sandbox is its own container. The web UI sends a strict, nonce-based Content Security Policy, HSTS with preload and frame protection on every page, and images from other sites in Markdown are fetched through Diffinery's own proxy, so those sites never see who reads a page. ## Reviewed before release Diffinery's code was audited area by area in October 2026: identity and tokens, Git and storage, Actions and secrets, the agent features and MCP, the web UI and REST API, the GitHub importer, and Diffinery's own CI and deploys. The [Security overview](https://diffinery.com/docs/security/overview) documents the whole model in detail. ## Report a vulnerability If you find a security problem, please tell us privately through the [report form](https://diffinery.com/security/report), the contact in [`/.well-known/security.txt`](https://diffinery.com/.well-known/security.txt). Good-faith research is covered by a safe harbour. See [Reporting a vulnerability](https://diffinery.com/docs/security/disclosure). --- # Git hosting and CI built entirely on Cloudflare > How open-source Diffinery runs Git hosting and GitHub Actions–compatible CI in your own Cloudflare account on Workers, Durable Objects, R2, D1 and Containers. Source: https://diffinery.com/built-on-cloudflare (last updated 2026-10-25) Diffinery is an open-source (Apache-2.0) git forge and CI platform that runs entirely on Cloudflare, and you deploy it to your own Cloudflare account. There are no servers, virtual machines or databases behind it that anyone has to run: one Cloudflare Worker and the Cloudflare products it uses serve Git, pull requests, the REST API, the MCP server and the container registry, and every workflow job runs in a Cloudflare Container started for that job. Diffinery is an open-source platform where Git hosting, pull requests with reviews in a web UI and GitHub Actions–compatible CI, marketplace actions included, all run on Cloudflare (checked October 25, 2026; see [Other Git and CI projects on Cloudflare](https://diffinery.com/built-on-cloudflare#other-git-and-ci-projects-on-cloudflare)). This page explains how to run your own instance, which Cloudflare product does what, what that means for the people using it, how it differs from Cloudflare's own Workers Builds and from other projects on Cloudflare, and the limits that come with it. ## Run Diffinery on your own Cloudflare account Diffinery is free, open-source software under the Apache-2.0 license. There is no hosted service to sign up for: you deploy your own instance to your own Cloudflare account, with your own domain, and run it as you like. Because Diffinery is one Worker plus the Cloudflare products it binds to, an instance needs a Cloudflare account on the Workers Paid plan, a domain on that account and a Cloudflare Zero Trust organization, and no machines to look after. The repository's Deploy workflow creates what's missing in your account and deploys the Worker, and every step of it is safe to repeat. - **Source code:** [diffinery.com/codician/diffinery](https://diffinery.com/codician/diffinery), where Diffinery is developed, mirrored on GitHub at [github.com/codician-team/diffinery](https://github.com/codician-team/diffinery). Issues and pull requests are welcome on the GitHub mirror from people without a diffinery.com account. - **Deploying:** [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy) walks through it step by step. [Self-hosting](https://diffinery.com/docs/self-hosting) gives the overview, [Configuration](https://diffinery.com/docs/self-hosting/configuration) lists every setting and [Architecture](https://diffinery.com/docs/self-hosting/architecture) explains how the parts fit. - **What it costs:** Diffinery itself is free. You pay Cloudflare for what your instance uses. It needs the Workers Paid plan, which has "a minimum cost of $5 USD per month per account", plus usage above the included amounts ([Workers pricing](https://developers.cloudflare.com/workers/platform/pricing/), checked October 25, 2026). Runner containers are billed by the 10 ms while a job runs ([Containers pricing](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026). - **Who needs a Cloudflare account:** only the deployment. Nobody who uses your instance needs one; they sign in with passkeys. Every instance is invite-only by default, and `SIGNUP=open` opens sign-up. ## Which Cloudflare product runs what This is the same mapping as the [Architecture](https://diffinery.com/docs/self-hosting/architecture) documentation, which goes into more detail. | Cloudflare product | What it runs in Diffinery | | --- | --- | | Workers | The web UI and the public docs, Git over HTTPS, Git LFS, the REST API, the MCP server, the container registry, the runner API, and the Actions cache and artifact services. The Worker holds no state of its own: it signs the caller in, checks their role and hands the request to the right repository. | | Durable Objects with SQLite, one per repository | Everything inside one repository: branches and tags, git objects, issues, pull requests, reviews, checks and commit statuses, releases, environments, workflow runs, secrets, webhooks and the merge queue. Live run logs and pull request updates reach the browser over the object's WebSockets. | | R2 | Anything too large for SQLite: git objects over 512 KiB compressed, Git LFS files, archived job logs, Actions caches and artifacts, container image layers, release assets and cached source archives. | | D1 | Data that belongs to no single repository: accounts, organizations, tokens, the list of repositories and who can reach them, invitations, notifications, the audit log and the container registry's index. | | Queues | Webhook deliveries and their retries, notifications, audit log entries and email jobs, sent in the background so the request that caused them doesn't wait. | | Workflows | Every workflow run, as a durable Cloudflare Workflow whose steps and waits survive restarts and deploys. GitHub imports and account exports run as Workflows too. | | Containers | Hosted job runners (one container per job), agent sandboxes, and the Git transfer of each GitHub import. | | Durable Object alarms and Cron Triggers | Scheduled workflows, checked every 5 minutes, and housekeeping such as registry cleanup and token expiry reminders. | | Email Sending | Every email Diffinery sends: invitations, notifications and security emails. | | Cloudflare Access | Only email-based account recovery and the first administrator's sign-in. Everyday sign-in is passkeys. | ## How a push and a workflow run move through it 1. `git push` reaches the Worker, which checks your token and your role on the repository and passes the push to the repository's Durable Object. 2. The object scans every new file for leaked credentials ([push protection](https://diffinery.com/docs/security/push-protection)), stores the objects (small ones in its SQLite database, large ones in R2), checks branch protection and moves each branch with a compare-and-swap, so two pushes to the same branch are applied one after the other. 3. It reads `.github/workflows/*.yml` from the pushed commit and starts a Cloudflare Workflow for each run that matches. 4. The Workflow plans the job graph and starts each job as soon as the jobs it `needs` have finished. For each job, the repository's object starts a fresh Cloudflare Container. 5. The runner in the container fetches its job, checks out the code and runs the steps. Logs stream to the repository's object and on to any browser watching; caches and artifacts go to R2. 6. When the job ends the container stops, and the Workflow starts whatever jobs were waiting on it. ## What this means for you - **No servers to run.** Your instance is a Worker and the Cloudflare products it binds to, so there is nothing to provision, patch or scale: no CI machines, no runner fleet and no database. Workflow files, `gh` and your editor work as they do with GitHub. - **Jobs start in seconds.** A fresh container per job starts in about 3 to 5 seconds, and the first job runs 6 to 8 seconds after `git push` returns (measured on October 16, 2026; see [Performance](https://diffinery.com/performance)). - **Runners exist only while a job runs.** Diffinery starts a container when a job starts and stops it when the job ends, so no runner sits idle between jobs. Cloudflare bills a container by the 10 ms while it runs: its memory and disk for what its instance type provides, and its CPU by use ([Cloudflare Containers pricing](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026). That's why Diffinery picks a smaller runner for jobs that mostly wait, when their own measured runs show it serves them just as well ([Runner sizes](https://diffinery.com/docs/actions/runners#runner-sizes)). Over 24 hours on October 16, 2026, runner containers ran 6% longer than the jobs in them, for starting and stopping. Diffinery itself is free; what the containers use is billed to the Cloudflare account your instance runs in. - **One busy repository never slows another.** Each repository is its own Durable Object with its own database, the single writer for everything in it, so ref updates, merges and run state are strongly consistent without locks. - **Runs survive restarts.** A workflow run is a durable Workflow, so a deploy or a restart doesn't lose it. A deploy is set up not to replace the container of a running job, so jobs normally finish on the version they started with. - **Cloudflare's network.** Requests are answered by the Worker at the Cloudflare location that receives them, and hosted jobs run in Cloudflare locations around the world: a 40-job probe on October 16, 2026 landed in North America, Europe and Japan. Each job's log names where it ran. A repository's own data lives in its Durable Object, in one place, so pages that read a repository make a trip to wherever that object is. ## Diffinery and Cloudflare Workers Builds Cloudflare has its own build service, Workers Builds. In Cloudflare's words, it lets you "integrate with Git and automatically build and deploy your Worker when pushing a change", for a Worker connected to "a repository hosted by Artifacts, GitHub, or GitLab". A build runs an optional build command and then a deploy command, which defaults to `npx wrangler deploy`; builds of the production branch create a new version of the Worker, and other branches get a Preview ([Workers Builds](https://developers.cloudflare.com/workers/ci-cd/builds/) and [its configuration](https://developers.cloudflare.com/workers/ci-cd/builds/configuration/), checked October 25, 2026). Diffinery does a different job: | | Diffinery | Cloudflare Workers Builds | | --- | --- | --- | | What it is | A git forge with pull requests, issues, releases, a container registry and GitHub Actions–compatible CI | A build and deploy service for Workers projects | | Where your code lives | On your Diffinery instance, in your own Cloudflare account | Artifacts, GitHub or GitLab | | What it runs | Any GitHub Actions workflow: tests, matrices, Docker, service containers, any language, on push, pull request, schedule and other triggers | A build command and a deploy command for a Worker | | What it deploys | Whatever your workflow deploys, including Workers with `wrangler deploy` | The connected Worker | They work together. A Diffinery repository doesn't appear in Workers Builds's list of repositories, so [Deploy to Cloudflare Workers](https://diffinery.com/docs/actions/deploy-to-cloudflare-workers) shows two ways to deploy automatically: a Diffinery Actions job that runs `wrangler deploy` on every push to `main` and gives each pull request its own Worker Preview (this is how Diffinery deploys itself), or a mirror of the branch to Cloudflare Artifacts for Workers Builds to build. ## Other Git and CI projects on Cloudflare Cloudflare has made Git on its network a theme in 2026, and Diffinery isn't the only open-source project there. Here is what we found when we checked each one's own documentation and code on October 25, 2026, and how each differs: | | Git hosting | Pull requests | CI on Cloudflare | Runs GitHub Actions workflows | | --- | --- | --- | --- | --- | | Diffinery (open source, Apache-2.0) | Yes, in your own Cloudflare account; no hosted service ([source](https://diffinery.com/codician/diffinery)) | Yes, with reviews and a merge queue | Yes, Cloudflare Containers | Yes, marketplace actions included ([differences](https://diffinery.com/docs/actions/compatibility)) | | Cloudflare Artifacts with Cloudflare's CI SDK | Yes: Git-compatible repositories on Cloudflare ([source](https://developers.cloudflare.com/artifacts/)) | Not offered | Yes: pipelines written in TypeScript, run as Workflows in sandboxes when a repository is pushed ([source](https://blog.cloudflare.com/ci-workflows/), August 4, 2026) | No: TypeScript instead of YAML workflows ([source](https://blog.cloudflare.com/ci-workflows/)) | | Flare Forge (open source, hosted demo) | Yes, on Artifacts ([source](https://github.com/everyai-com/flare-forge)) | Replaced by "intents" ([source](https://github.com/everyai-com/flare-forge)) | Yes, Cloudflare Containers ([source](https://github.com/everyai-com/flare-forge)) | Partly: workflow files are translated to its own format, and JavaScript and container `uses:` steps are dropped with a warning ([source](https://github.com/everyai-com/flare-forge/blob/main/apps/worker/src/actionsCompat.ts)) | | git-forge by levino (open source, MIT) | Yes, in your own Cloudflare account; no hosted service ([source](https://github.com/levino/git-forge)) | Listed, with "the web UI and collaboration features are next" ([source](https://github.com/levino/git-forge)) | Yes, Cloudflare Containers since October 18, 2026, when its "CI runners on Cloudflare Containers" pull request was merged ([source](https://github.com/levino/git-forge/pull/61)); its README still says "not yet deployed" ([source](https://github.com/levino/git-forge)) | Yes, real workflows with the official `actions/runner` ([source](https://github.com/levino/git-forge)) | Projects that only run GitHub's self-hosted runner in Cloudflare Containers keep the code and the pull requests on GitHub, so they aren't on this list. We re-check these projects when we update this page, and change the comparison when one of them changes. ## Deploying to Cloudflare from Diffinery CI The recommended setup is a workflow like any GitHub Actions deploy: store a Cloudflare API token and your account ID as repository secrets, then run Wrangler in a job. ```yaml jobs: deploy: if: github.event_name == 'push' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 cache: npm - run: npm ci - run: npx wrangler deploy env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} ``` The full guide, with Previews per pull request and keeping the production token in an environment, is [Deploy to Cloudflare Workers](https://diffinery.com/docs/actions/deploy-to-cloudflare-workers). For clouds that accept OpenID Connect, jobs can use short-lived [OIDC](https://diffinery.com/docs/actions/oidc) tokens instead of stored keys. ## Limits that come with building on Cloudflare - **Hosted runners are Linux x64 only.** Cloudflare Containers run Linux, so there are no hosted macOS or Windows runners, and every `ubuntu-*` label, including `ubuntu-24.04-arm`, gets the same Ubuntu 24.04 x64 image. Use [self-hosted runners](https://diffinery.com/docs/actions/runners#self-hosted-runners) for macOS, Windows, Arm and GPUs. - **At most 4 vCPUs and 12 GiB per hosted job.** The largest runner is Cloudflare's `standard-4` instance type; there are no larger hosted sizes. - **Hosts span CPU generations.** Cloudflare's hosts mix AMD EPYC generations whose cores differ about 2x in speed, and nobody picks which one a job lands on. The same job can run up to about twice as fast on one host as on another; each job's log names the host's processor, and the ranges on [Performance](https://diffinery.com/performance) include the slow hosts. - **Jobs sometimes wait for a machine.** When many jobs start at once, a container occasionally isn't placed or stops before its runner starts. Diffinery puts the job back in line and tries again on its own; it usually costs the job up to a minute or two. See [Runners troubleshooting](https://diffinery.com/docs/actions/runners#troubleshooting). - **A push carries at most 100 MB.** Use [Git LFS](https://diffinery.com/docs/repositories/git-lfs) for large files. Container image layers larger than Cloudflare's 100 MB request limit push from hosted runners through a relay that splits them, but not from self-hosted runners. - **Clones send more bytes than GitHub's.** Packs are sent without deltas, so clones and fetches download more data. See [Git over HTTPS](https://diffinery.com/docs/repositories/git#limits-and-differences-from-github). - **20 hosted jobs at once per account and 80 per instance, by default.** Further jobs wait their turn. An instance's administrators set these limits (`HOSTED_JOBS_LIMIT` and the `QUOTA_*` variables in [Configuration](https://diffinery.com/docs/self-hosting/configuration)). See [Limits](https://diffinery.com/docs/reference/limits). ## Frequently asked questions ### Is Diffinery open source? Yes. Diffinery is open source under the Apache-2.0 license, and nothing about it is sold. It is developed at [diffinery.com/codician/diffinery](https://diffinery.com/codician/diffinery) and mirrored on GitHub at [github.com/codician-team/diffinery](https://github.com/codician-team/diffinery). You run it by deploying your own instance to your own Cloudflare account; see [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy). ### What does it cost to run Diffinery? Diffinery itself is free. You pay Cloudflare for what your instance uses: it needs the Workers Paid plan, "a minimum cost of $5 USD per month per account", plus usage above the included amounts ([Workers pricing](https://developers.cloudflare.com/workers/platform/pricing/), checked October 25, 2026), and runner containers are billed by the 10 ms while a job runs ([Containers pricing](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026). ### Does Diffinery run on Cloudflare? Yes, entirely. A Cloudflare Worker serves the web UI, Git, the REST API and MCP; each repository is a Durable Object with its own SQLite database; large files live in R2 and accounts in D1; workflow runs are Cloudflare Workflows; and every workflow job runs in its own Cloudflare Container. See [Architecture](https://diffinery.com/docs/self-hosting/architecture). ### Is Diffinery the only Git and CI platform on Cloudflare? No. Other open-source projects run Git and CI on Cloudflare too; here's how they differ (checked October 25, 2026). Cloudflare Artifacts with Cloudflare's CI SDK runs TypeScript pipelines rather than GitHub Actions workflows and has no pull requests; Flare Forge uses "intents" instead of pull requests and drops JavaScript and container `uses:` steps from workflow files; and git-forge (MIT) runs real workflows with the official `actions/runner` on Cloudflare Containers since October 18, 2026, while its README says "the web UI and collaboration features are next". Diffinery has all three today: Git hosting, pull requests with reviews in a web UI, and GitHub Actions–compatible CI with marketplace actions. See [Other Git and CI projects on Cloudflare](https://diffinery.com/built-on-cloudflare#other-git-and-ci-projects-on-cloudflare). ### Is Diffinery the same as Cloudflare Workers Builds? No. Workers Builds builds and deploys a Worker from a repository on Artifacts, GitHub or GitLab. Diffinery hosts the repository itself, with pull requests and issues, and runs any GitHub Actions workflow, which can deploy a Worker among other things. ### Can I deploy to Cloudflare Workers from Diffinery? Yes. A workflow job runs `wrangler deploy` with a Cloudflare API token stored as a secret, and can give each pull request its own Worker Preview. See [Deploy to Cloudflare Workers](https://diffinery.com/docs/actions/deploy-to-cloudflare-workers). ### Does Docker work on runners in Cloudflare Containers? Yes. Job containers, service containers, Docker actions, `docker build` and `docker compose` work as on GitHub's runners. The Docker daemon starts the first time a job uses it, or as the job begins when the workflow uses Docker. See [Docker in workflows](https://diffinery.com/docs/actions/docker). --- # GitHub and GitHub Actions alternatives, compared > How Diffinery compares with GitHub, GitLab, Bitbucket, Gitea, Forgejo, CircleCI, Buildkite and GitHub Actions runner services such as Blacksmith and Depot. Source: https://diffinery.com/compare (last updated 2026-10-25) Teams that want faster or cheaper CI than GitHub Actions have three kinds of options: keep GitHub and run jobs on another company's runners, keep their Git host and move CI to a separate CI service such as CircleCI or Buildkite, or move to a forge that hosts the code and runs the CI. Diffinery is the last kind: a git forge that runs GitHub Actions workflows as they are, on fast runners, with AI agents as accounts held to guardrails. It is free, open-source software (Apache-2.0) that you deploy to your own Cloudflare account and domain; there is no hosted service to sign up for. See [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy) and the [source code](https://diffinery.com/codician/diffinery), mirrored [on GitHub](https://github.com/codician-team/diffinery). Diffinery is an open-source platform where Git hosting, pull requests with reviews in a web UI and GitHub Actions–compatible CI, marketplace actions included, all run on Cloudflare (checked October 25, 2026; see [Built on Cloudflare](https://diffinery.com/built-on-cloudflare#other-git-and-ci-projects-on-cloudflare)). Every fact about another product on these pages comes from that product's own website or documentation, linked and dated. Diffinery's numbers are measured on the runners of diffinery.com, the instance Diffinery is developed on; see [Performance](https://diffinery.com/performance) and [how we check what we publish](https://diffinery.com/about#how-we-check-what-we-publish). ## The detailed comparisons - [Diffinery vs GitHub](https://diffinery.com/compare/github): code hosting, pull requests, GitHub Actions, AI agents and security. - [Diffinery vs GitLab](https://diffinery.com/compare/gitlab): CI format, hosted runners, compute minutes and AI features. - [Diffinery vs Blacksmith](https://diffinery.com/compare/blacksmith): a GitHub Actions runner service, against a forge with runners built in. - [Diffinery vs Depot](https://diffinery.com/compare/depot): runners, Depot CI and container builds, against a forge with CI built in. - [Diffinery vs CircleCI](https://diffinery.com/compare/circleci): a CI service for code on GitHub, GitLab or Bitbucket, against a forge with CI built in. - [Diffinery vs Buildkite](https://diffinery.com/compare/buildkite): hybrid CI on agents you run or Buildkite hosts, against hosted runners built into a forge. - [Diffinery vs Bitbucket](https://diffinery.com/compare/bitbucket): Bitbucket Cloud and Bitbucket Pipelines, build minutes, runner sizes and Jira. - [Diffinery vs Gitea and Forgejo](https://diffinery.com/compare/gitea): self-hosted open-source forges with Actions-style CI, against an open-source forge that runs on Cloudflare. ## Two ways to speed up GitHub Actions | | Keep GitHub, change runners | Move to Diffinery | | --- | --- | --- | | What changes | The `runs-on` label of each job, and a GitHub App that gives the vendor access | Where your repositories live: a Diffinery instance you deploy to your own Cloudflare account; workflow files stay as they are | | Who runs it | GitHub and the runner service run everything for you | You do, on your own Cloudflare account; there is no hosted service | | Cost | GitHub's plans plus the runner service's prices | Free and open source (Apache-2.0); you pay Cloudflare for your instance's usage | | Pull requests and reviews | GitHub's | Diffinery's | | macOS and Windows | Offered by most runner services | Self-hosted runners only | | AI agents | Whatever GitHub offers | Agent accounts, server-enforced guardrails, MCP, sandboxes, tasks and review | ## GitHub Actions runner services at a glance Published list prices for a Linux x64 runner with 2 vCPUs, and what each service runs on. Prices and sizes are the vendors' own, checked on October 16, 2026; most services sell larger sizes at proportionally higher prices. | Service | What it is | Linux x64, 2 vCPU | Other platforms | Hosts your code | | --- | --- | --- | --- | --- | | GitHub-hosted runners | GitHub's own runners | $0.006/min, each job rounded up to the minute ([source](https://docs.github.com/en/billing/reference/actions-runner-pricing)) | Arm, Windows, macOS | Yes (GitHub) | | [Blacksmith](https://diffinery.com/compare/blacksmith) | Managed runners in Firecracker microVMs on gaming-class CPUs | $0.004/min; 3,000 free minutes a month per organization ([source](https://www.blacksmith.sh/pricing)) | Arm, Windows (beta), macOS | No | | [Depot](https://diffinery.com/compare/depot) | Managed runners on AWS, plus Depot CI and container builds | $0.006/min, tracked per second; plans from $20 a month ([source](https://depot.dev/pricing)) | Arm, Windows, macOS | Depot Code, in beta | | Namespace | Managed runners configured through profiles | $0.004/min prepaid for 2 vCPU with 8 GB ($0.002 with 4 GB); plans from $0 ([source](https://namespace.so/pricing)) | Arm, Windows, macOS | No | | WarpBuild | Managed runners, or runners in your own cloud account | $0.004/min ([source](https://www.warpbuild.com/pricing)) | Arm, Windows (from 4 vCPU), macOS | No | | RunsOn | Runners in your own AWS account, under an annual license | Your AWS bill; RunsOn estimates about $0.0009/min on spot ([source](https://runs-on.com/pricing/)) | Arm, Windows, GPUs; no macOS | No | | Ubicloud | Managed runners on Ubicloud's open-source cloud in Germany | $0.002/min premium (default), $0.00125/min standard ([source](https://www.ubicloud.com/docs/about/pricing)) | Arm | No | | **Diffinery** | An open-source git forge whose CI runs GitHub Actions workflows, deployed to your own Cloudflare account | Free and open source (Apache-2.0); you pay Cloudflare for your instance's usage. The default runner has 4 vCPU and 12 GiB | Self-hosted runners | Yes (your instance) | BuildJet, another runner service, has shut down ([source](https://buildjet.com/for-github-actions)). Diffinery has no per-minute price of its own. Your instance needs Cloudflare's Workers Paid plan, "a minimum cost of $5 USD per month per account", plus usage above the included amounts ([source](https://developers.cloudflare.com/workers/platform/pricing/), checked October 25, 2026), and its runner containers are billed by the 10 ms while a job runs ([source](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026). The runner services above run everything for you; with Diffinery, you run the instance. ## CI platforms that aren't GitHub runner services Some teams leave GitHub Actions for another CI system, either a separate service next to their Git host or the CI built into another forge. Facts are the vendors' own, checked on October 25, 2026; the linked comparisons have the details and sources. | Platform | What it is | Pipeline format | Runs GitHub Actions workflow files | Hosts your code | Hosted Linux x64, 2 vCPU | | --- | --- | --- | --- | --- | --- | | [CircleCI](https://diffinery.com/compare/circleci) | A CI service for code on GitHub, GitLab or Bitbucket, with a self-hosted edition | `.circleci/config.yml` | In preview: GitHub repositories, Linux only ([source](https://circleci.com/docs/guides/orchestrate/use-a-github-actions-workflow-file-as-your-pipeline-configuration/)) | No | $0.006/min (10 credits at $0.0006) for Docker Medium with 4 GB ([source](https://circleci.com/pricing/price-list/)) | | [Buildkite](https://diffinery.com/compare/buildkite) | A hosted control plane, with jobs on agents you run or Buildkite hosts | `.buildkite/pipeline.yml`, which can be generated during a build | In public preview ([source](https://buildkite.com/docs/pipelines/migration/run-github-actions-workflows)) | No | $0.008/min for Small with 4 GB ([source](https://buildkite.com/pricing/)) | | [Bitbucket Pipelines](https://diffinery.com/compare/bitbucket) | CI built into Atlassian's Bitbucket Cloud | `bitbucket-pipelines.yml` | No | Yes (Bitbucket) | Counted in build minutes: 2,500 a month on Standard, then $10 per 1,000 ([source](https://www.atlassian.com/licensing/bitbucket)) | | [GitLab CI](https://diffinery.com/compare/gitlab) | CI built into GitLab | `.gitlab-ci.yml` | No; GitLab documents rewriting workflows as `.gitlab-ci.yml` ([source](https://docs.gitlab.com/ci/migration/github_actions/)) | Yes (GitLab) | Counted in compute minutes: 400 a month on Free, then $10 per 1,000 ([source](https://about.gitlab.com/pricing/)) | | [Gitea Actions](https://diffinery.com/compare/gitea) | CI built into Gitea, a self-hosted open-source forge | GitHub Actions–style YAML in `.gitea/workflows/` | "Mostly compatible", in Gitea's words ([source](https://docs.gitea.com/usage/actions/overview)) | Yes (your server, or Gitea Cloud) | Runners you run; Gitea Cloud starts them for you | | [Forgejo Actions](https://diffinery.com/compare/gitea) | CI built into Forgejo, a self-hosted open-source forge | GitHub Actions–style YAML in `.forgejo/workflows/` | "Not designed to be compatible", in Forgejo's words, though familiar ([source](https://forgejo.org/docs/latest/user/actions/overview/)) | Yes (your server, or Codeberg for free software) | Runners you run | | **Diffinery** | An open-source git forge whose CI runs GitHub Actions workflows, deployed to your own Cloudflare account | GitHub Actions YAML in `.github/workflows/` | Yes, with every difference listed in [Compatibility](https://diffinery.com/docs/actions/compatibility) | Yes (your instance) | Runners in Cloudflare Containers that your instance starts per job; you pay Cloudflare for their usage. The default runner has 4 vCPU and 12 GiB | ## Forges at a glance | | Diffinery | GitHub | GitLab.com | | --- | --- | --- | --- | | Who runs it | You, on your own Cloudflare account | GitHub; GitHub Enterprise Server runs on your own servers | GitLab; GitLab also has a self-managed edition | | CI format | GitHub Actions YAML | GitHub Actions YAML | `.gitlab-ci.yml` | | Default hosted Linux runner | 4 vCPU, 12 GiB | 2 vCPU, 8 GB on private repositories; 4 vCPU, 16 GB on public ones | 2 vCPU, 8 GB | | Hosted macOS and Windows | No | Yes | Beta | | Guardrails for AI agents | Built in for every agent account | Rulesets and token permissions you configure | Protected branches, approval rules and service accounts you configure | | Built-in MCP server | Yes | Yes | Yes | | Push protection for every repository by default | Yes | Public repositories; private ones with a paid add-on | Ultimate tier | | Forks | No | Yes | Yes | | Price | Free and open source (Apache-2.0); you pay Cloudflare for your instance's usage | Free, Team $4, Enterprise from $21 per user per month | Free, Premium $29, Ultimate on request | Sources: [GitHub vs Diffinery](https://diffinery.com/compare/github) and [GitLab vs Diffinery](https://diffinery.com/compare/gitlab), where every row is linked to the vendor's page. ## Frequently asked questions ### What's the best alternative to GitHub Actions? It depends on what you want to keep. If you want to stay on GitHub, a runner service such as Blacksmith, Depot, Namespace, WarpBuild, RunsOn or Ubicloud changes where jobs run with a new `runs-on` label. If you want faster CI and are willing to move your repositories and run your own instance on Cloudflare, Diffinery runs the same workflow files on 4-vCPU runners and also hosts your code, pull requests and AI agents. If you'd rather not run anything yourself, a runner service is the simpler choice. ### Is there a GitHub alternative that runs GitHub Actions workflows? Yes. Diffinery reads `.github/workflows/*.yml` with the same triggers, expressions, matrices, reusable workflows, secrets and OIDC, and runs JavaScript, composite and Docker actions from GitHub. See [Compatibility with GitHub Actions](https://diffinery.com/docs/actions/compatibility). ### Which CI platforms can run GitHub Actions workflow files outside GitHub? Diffinery runs them as its main format, on its own repositories. CircleCI and Buildkite both offer it in preview, with limits listed in their documentation, for code that stays on GitHub. Gitea Actions describes itself as "mostly compatible" with GitHub Actions, and Forgejo Actions as familiar but "not designed to be compatible"; both run on runners you set up. See the table above and the detailed comparisons for the sources. ### Which platform is built for AI coding agents? Diffinery treats agents as accounts of their own, with guardrails the server enforces: no pushes to protected branches, a person's approval on every agent pull request, and no secrets for agent-written code. See [Diffinery for AI agents](https://diffinery.com/agents). ### How much does Diffinery cost? Diffinery itself is free and open source under the Apache-2.0 license. You deploy it to your own Cloudflare account and pay Cloudflare for what your instance uses: the Workers Paid plan, "a minimum cost of $5 USD per month per account", plus usage above the included amounts ([source](https://developers.cloudflare.com/workers/platform/pricing/), checked October 25, 2026), and runner containers billed by the 10 ms while a job runs ([source](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026). There are no plans or paid tiers. See [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy). ### Does everyone on my team need a Cloudflare account? No. Only the deployment needs one. People who use your instance need only an account on that instance, and sign in with a passkey. --- # Diffinery vs GitHub > How Diffinery compares with GitHub and GitHub Actions on CI speed, runners, workflow compatibility, AI agents, security and features, with sources and dates. Source: https://diffinery.com/compare/github (last updated 2026-10-25) Diffinery is a git forge and CI platform that runs GitHub Actions workflows as they are. If you're on GitHub today, this page sets out what changes if you move, what gets better, and what GitHub still does that Diffinery doesn't. GitHub facts are from GitHub's own documentation and pricing pages, checked on October 16, 2026, and linked below. Diffinery's speed figures are measured; see [Performance](https://diffinery.com/performance). Diffinery is free, open-source software (Apache-2.0) that you deploy to your own Cloudflare account and domain; there is no hosted service, so moving from GitHub also means running your own instance. See [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy) and the [source code](https://diffinery.com/codician/diffinery), mirrored [on GitHub](https://github.com/codician-team/diffinery). Diffinery is an open-source platform where Git hosting, pull requests with reviews in a web UI and GitHub Actions–compatible CI, marketplace actions included, all run on Cloudflare (checked October 25, 2026; see [Built on Cloudflare](https://diffinery.com/built-on-cloudflare#other-git-and-ci-projects-on-cloudflare)). ## In short - **Choose Diffinery** if your team runs CI on private repositories and wants faster runners by default, uses AI coding agents and wants the server to enforce limits on them, works on Linux, and is happy to run its own instance on Cloudflare. - **Stay on GitHub** if you need hosted macOS, Windows or Arm runners, forks for outside contributors, GitHub's app marketplace, Codespaces, Pages or Discussions, if you're an open-source project that depends on GitHub's network, or if you'd rather not run anything yourself: GitHub runs github.com for you, while a Diffinery instance is yours to deploy, update and pay Cloudflare for. - **Moving is mostly mechanical.** Diffinery's importer copies repositories with history, issues, pull requests, reviews and releases, workflow files run unchanged, and `gh`, VS Code, Cursor and JetBrains IDEs keep working. ## CI and runners | | Diffinery | GitHub Actions | | --- | --- | --- | | Workflow syntax | GitHub Actions YAML, read from `.github/workflows/` as is. Differences are listed in [Compatibility](https://diffinery.com/docs/actions/compatibility). | GitHub Actions YAML | | Default Linux runner, private repositories | 4 vCPU, 12 GiB memory, 20 GB disk | 2 vCPU, 8 GB memory, 14 GB SSD ([source](https://docs.github.com/en/actions/reference/runners/github-hosted-runners)) | | Default Linux runner, public repositories | 4 vCPU, 12 GiB memory, 20 GB disk | 4 vCPU, 16 GB memory, 14 GB SSD ([source](https://docs.github.com/en/actions/reference/runners/github-hosted-runners)) | | Smaller runners | 2, 1/2 and 1/4 vCPU, picked per job from its measured runs, or by label | 1 vCPU `ubuntu-slim`, with a 15-minute job limit ([source](https://docs.github.com/en/actions/reference/runners/github-hosted-runners)) | | Larger runners | Not available above 4 vCPU | Linux up to 96 vCPU, on the Team and Enterprise Cloud plans, billed per minute ([source](https://docs.github.com/en/actions/reference/runners/larger-runners)) | | Hosted macOS, Windows, Arm, GPU | Not available; use self-hosted runners | Available | | Job start | About 3 to 5 s (measured) | No published figure | | Common actions | `checkout`, `setup-node`, `setup-python`, `setup-go`, `cache` and artifact actions built into the runner | Downloaded and run per job | | Preinstalled toolchains | A small image: Node.js, Python, Docker, gh, build tools. Go and Java install while checkout runs (1 to 5 s). | A large image with most toolchains preinstalled | | Self-hosted runners | `diffinery runner`, on any machine | GitHub's runner application | | Max job time | 6 hours | 6 hours ([source](https://docs.github.com/en/actions/reference/limits)) | | Concurrent hosted jobs | 20 per account by default; your instance's administrators set it ([Configuration](https://diffinery.com/docs/self-hosting/configuration)) | 20 on Free, 40 on Pro, 60 on Team, 500 on Enterprise ([source](https://docs.github.com/en/actions/reference/limits)) | | Linux runner price | Free and open source (Apache-2.0); you pay Cloudflare for your instance's usage, with runner containers billed by the 10 ms while a job runs ([source](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026) | $0.006 per minute for 2-core, $0.012 for 4-core, each job rounded up to the whole minute ([source](https://docs.github.com/en/billing/reference/actions-runner-pricing)) | GitHub cut its hosted runner prices by up to 39% on January 1, 2026 ([changelog](https://github.blog/changelog/2026-01-01-reduced-pricing-for-github-hosted-runners-usage/)); the figures above are the current ones. ## Code hosting and collaboration | | Diffinery | GitHub | | --- | --- | --- | | Who runs it | You, on your own Cloudflare account and domain ([guide](https://diffinery.com/docs/self-hosting/deploy)) | GitHub runs github.com; GitHub Enterprise Server runs on your own servers | | Git over HTTPS | Yes | Yes | | Git over SSH | No | Yes | | Git LFS | Yes | Yes | | Pull requests, reviews, required approvals and checks | Yes, plus an `intent` field saying what a change is for | Yes | | Suggested changes, pending reviews, resolving threads | Not yet | Yes | | Forks | No: pull requests are between branches of one repository | Yes | | Auto-merge and merge queue | Yes, with GitHub's `merge_group` event | Yes | | Issues, labels, milestones, releases | Yes | Yes | | Projects, Discussions, wikis, Pages, Codespaces | No | Yes | | Container registry | Yes, at `//` | Yes, ghcr.io | | REST API | GitHub-style at `/api/v3`, with a GraphQL endpoint for `gh` | Yes | | `gh` CLI | Works, as with GitHub Enterprise Server | Yes | | App marketplace and GitHub Apps | No | Yes | ## AI agents | | Diffinery | GitHub | | --- | --- | --- | | Agent identity | An agent account of its own, owned by a person or organization, with its own tokens | Usually a person's token, a GitHub App or a bot account | | Guardrails enforced by the server | Agents can't push to protected branches, their pull requests need a person's approval, their checks never satisfy required checks, and runs of their code get no secrets | Configured per repository with rulesets and permissions | | MCP server | At `/mcp` on your instance, with browser sign-in | The GitHub MCP Server, generally available since September 2025 ([source](https://github.blog/changelog/2025-09-04-remote-github-mcp-server-is-now-generally-available/)) | | Agent that turns an issue or goal into a pull request | [Agent tasks](https://diffinery.com/docs/agents/tasks) run Claude Code, Codex or your own command with your own model key | Copilot cloud agent, on paid Copilot plans ([source](https://docs.github.com/en/copilot/concepts/enterprise/cloud-agent-access)) | | AI pull request review | [Agent review](https://diffinery.com/docs/agents/review) with your own model key | Copilot code review, on paid Copilot plans ([source](https://docs.github.com/en/copilot/concepts/agent-capabilities/agent-powered-workflows-and-operations/code-review)) | | Sandboxes for agents | Yes, over MCP and the REST API | Codespaces, and the Copilot agent's own environment | ## Security | | Diffinery | GitHub | | --- | --- | --- | | Sign-in | Passkeys only | A password with two-factor authentication (required for everyone who contributes code since 2023), or a passkey ([source](https://docs.github.com/en/authentication/authenticating-with-a-passkey/about-passkeys)) | | Push protection for leaked credentials | On for every repository, private ones included, for every push and every commit made through the API or MCP | On by default for pushes to public repositories; for private repositories it needs GitHub Secret Protection, a paid add-on ([source](https://docs.github.com/en/code-security/concepts/secret-security/push-protection)) | | Secrets for workflow runs of agent-written code | Never given | Depends on your configuration | | Audit log | Yes, append-only, for every account | Organization owners can review it; the audit log API and streaming need Enterprise Cloud ([source](https://docs.github.com/en/enterprise-cloud@latest/organizations/keeping-your-organization-secure/managing-security-settings-for-your-organization/reviewing-the-audit-log-for-your-organization)) | ## Moving from GitHub First, deploy your own instance to your Cloudflare account; see [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy). Then: 1. Import a repository or a whole organization from **Settings → Imports**, or with `diffinery migrate github`. History, issues, pull requests, reviews, comments, labels, milestones, releases, branch protection, variables and secret names come across, with their numbers. 2. Enter each secret's value (GitHub never reveals them, so no tool can copy them). 3. Point your clones at Diffinery and sign `gh` in with `diffinery auth setup-gh`. 4. Push. Your workflows run on your instance's runners. See [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github) for the full guide. ## Frequently asked questions ### Do GitHub Actions workflows run on Diffinery without changes? Most do. Diffinery reads `.github/workflows/*.yml` with the same triggers, expressions, matrices, reusable workflows, secrets, OIDC and Docker support, and runs JavaScript, composite and Docker actions from GitHub. Jobs that need hosted macOS, Windows or Arm runners need a self-hosted runner instead. Every difference is listed in [Compatibility with GitHub Actions](https://diffinery.com/docs/actions/compatibility). ### Is Diffinery faster than GitHub Actions? For CPU-heavy jobs on private repositories, usually yes: Diffinery's default runner has 4 vCPUs where GitHub's standard private-repository runner has 2, and jobs start in about 3 to 5 seconds. Setup steps such as checkout and cache restores are at or near parity. GitHub is still up to about 4 seconds faster at setting up Go and Java, which it preinstalls. See [Performance](https://diffinery.com/performance) for the measurements. ### Can I keep using the GitHub CLI and my editor? Yes. `gh` works with Diffinery as it does with GitHub Enterprise Server, VS Code, Cursor and Windsurf can clone from Diffinery, and JetBrains IDEs get a plugin. ### Can I keep a copy on GitHub? Yes. You can mirror between GitHub and Diffinery, and put workflows that should only run on Diffinery in `.diffinery/workflows/`. See [Keep GitHub as upstream](https://diffinery.com/docs/migrate-from-github#keep-github-as-upstream-and-mirror-to-diffinery). ### How much does Diffinery cost? Diffinery itself is free and open source under the Apache-2.0 license; there are no plans or paid tiers. You deploy it to your own Cloudflare account and pay Cloudflare for what your instance uses: the Workers Paid plan, "a minimum cost of $5 USD per month per account", plus usage above the included amounts ([source](https://developers.cloudflare.com/workers/platform/pricing/), checked October 25, 2026), and runner containers billed by the 10 ms while a job runs ([source](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026). See [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy). --- # Diffinery vs GitLab > How Diffinery compares with GitLab.com on CI compatibility, hosted runners, compute minutes, AI agents and features, with sources and dates. Source: https://diffinery.com/compare/gitlab (last updated 2026-10-25) GitLab is a complete DevSecOps platform with its own CI system. Diffinery is a smaller, GitHub-compatible forge focused on fast CI and on AI agents as first-class collaborators. It is free, open-source software (Apache-2.0) that you deploy to your own Cloudflare account; there is no hosted service (see [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy) and the [source code](https://diffinery.com/codician/diffinery)). GitLab facts here are from GitLab's own documentation and pricing page, checked on October 16, 2026, and linked below. ## In short - **The biggest difference is the CI format.** GitLab CI uses `.gitlab-ci.yml`. Diffinery runs GitHub Actions workflows (`.github/workflows/*.yml`) as they are, so it suits teams coming from GitHub, or teams that want the GitHub Actions ecosystem of reusable actions. - **Choose GitLab** if you need its breadth: built-in security scanning, planning and portfolio tools, a self-managed edition on your own servers, hosted runners up to 32 vCPUs, hosted Windows and macOS runners (in beta), or a service that GitLab runs for you, with nothing to deploy. - **Choose Diffinery** if you want GitHub Actions compatibility, 4-vCPU runners by default, a forge built around AI agents with server-enforced guardrails, and open-source software that runs on your own Cloudflare account, with no servers or virtual machines to manage. ## CI and runners | | Diffinery | GitLab.com | | --- | --- | --- | | Pipeline format | GitHub Actions YAML | `.gitlab-ci.yml` | | Default hosted Linux runner | 4 vCPU, 12 GiB memory, 20 GB disk | small: 2 vCPU, 8 GB memory, 30 GB disk ([source](https://docs.gitlab.com/ci/runners/hosted_runners/linux/)) | | Other hosted Linux sizes | 2, 1/2 and 1/4 vCPU, picked per job from its measured runs | medium (4 vCPU) on every tier; large (8), xlarge (16) and 2xlarge (32) on Premium and Ultimate ([source](https://docs.gitlab.com/ci/runners/hosted_runners/linux/)) | | How bigger runners are counted | Each size runs on a Cloudflare Containers instance type, and Cloudflare bills your account by the 10 ms while a job runs ([source](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026) | Each minute on medium counts as 2 compute minutes, large 3, xlarge 6, 2xlarge 12 ([source](https://docs.gitlab.com/ci/pipelines/compute_minutes/)) | | Hosted macOS and Windows | Not available; use self-hosted runners | Both in beta: Windows on every tier, macOS on Premium and Ultimate ([macOS](https://docs.gitlab.com/ci/runners/hosted_runners/macos/), [Windows](https://docs.gitlab.com/ci/runners/hosted_runners/windows/)) | | Included CI minutes | Nothing to buy. By default each account gets 3,000 hosted minutes a month, a quota your instance's administrators set ([Configuration](https://diffinery.com/docs/self-hosting/configuration)) | 400 compute minutes a month on Free, 10,000 on Premium, 50,000 on Ultimate ([source](https://about.gitlab.com/pricing/)) | | Extra minutes | None to buy; you pay Cloudflare for your instance's usage | $10 per 1,000 compute minutes ([source](https://about.gitlab.com/pricing/)) | | Self-hosted runners | `diffinery runner` | GitLab Runner | ## Price and hosting | | Diffinery | GitLab.com | | --- | --- | --- | | Who runs it | You, on your own Cloudflare account and domain ([guide](https://diffinery.com/docs/self-hosting/deploy)) | GitLab runs GitLab.com; GitLab also has a self-managed edition | | Price | Free and open source (Apache-2.0); you pay Cloudflare for your instance's usage | Free $0 (up to 5 users per private top-level group), Premium $29 per user per month billed annually, Ultimate on request ([source](https://about.gitlab.com/pricing/)) | | Secret push protection | On for every repository | Ultimate tier ([source](https://docs.gitlab.com/user/application_security/secret_detection/secret_push_protection/)) | ## AI agents | | Diffinery | GitLab | | --- | --- | --- | | Accounts for agents and automation | Agent accounts with their own tokens, owned by a person or organization | Service accounts, on every tier ([source](https://docs.gitlab.com/user/profile/service_accounts/)) | | Server-enforced agent guardrails | No pushes to protected branches, a person approves every agent pull request, agent checks never satisfy required checks, no secrets for agent-written code | Configured with protected branches and approval rules | | MCP server | Built in, at `/mcp` on your instance | Built in, at `/api/v4/mcp`, on every tier ([source](https://docs.gitlab.com/user/model_context_protocol/mcp_server/)) | | AI features | [Agent tasks](https://diffinery.com/docs/agents/tasks) and [agent review](https://diffinery.com/docs/agents/review) run Claude Code, Codex or your own command with your own model key | GitLab Duo add-ons for Premium and Ultimate, and GitLab Credits ([source](https://docs.gitlab.com/subscriptions/subscription-add-ons/)) | ## Moving from GitLab Deploy your own instance first ([guide](https://diffinery.com/docs/self-hosting/deploy)). Diffinery's importer reads from GitHub. From GitLab, push your repositories with plain Git (`git push --mirror`), then rewrite pipelines as GitHub Actions workflows. See [Move with plain Git](https://diffinery.com/docs/migrate-from-github#move-with-plain-git). ## Frequently asked questions ### Does Diffinery run .gitlab-ci.yml? No. Diffinery runs GitHub Actions workflows. Teams moving from GitLab rewrite their pipelines as workflows in `.github/workflows/`. ### Is Diffinery a full GitLab replacement? Not for every team. Diffinery covers Git hosting, pull requests, issues, releases, CI, a container registry and AI agents. It doesn't have GitLab's built-in security scanners, planning and portfolio tools, larger hosted runners or hosted Windows and macOS runners. And GitLab.com is a service GitLab runs for you, where Diffinery is software you run on your own Cloudflare account. --- # Diffinery vs Blacksmith > Blacksmith speeds up GitHub Actions on its own runners while you stay on GitHub. Diffinery replaces GitHub and Actions together. Specs, prices, trade-offs. Source: https://diffinery.com/compare/blacksmith (last updated 2026-10-25) Blacksmith and Diffinery both make GitHub Actions workflows run faster, in different ways. Blacksmith sells drop-in runners for GitHub Actions: your code, pull requests and workflows stay on GitHub, and jobs run on Blacksmith's machines. Diffinery replaces GitHub and GitHub Actions together, with fast runners built in. Blacksmith is a service that runs the runners for you; Diffinery is free, open-source software (Apache-2.0) that you deploy to your own Cloudflare account, with no hosted service (see [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy) and the [source code](https://diffinery.com/codician/diffinery)). Blacksmith facts here are from its own website and documentation, checked on October 16, 2026, and linked below. ## In short - **Choose Blacksmith** if you want to stay on GitHub and only want faster or cheaper CI. It needs a GitHub App and a new `runs-on` label, and offers Linux, Arm, Windows and macOS runners up to 32 vCPUs, run for you with nothing to deploy. - **Choose Diffinery** if you want one platform for code, reviews and CI, with AI agents as accounts that the server holds to guardrails, and Linux runners that are 4 vCPU by default, and you're happy to run your own instance on Cloudflare. ## Side by side | | Diffinery | Blacksmith | | --- | --- | --- | | What it is | Git hosting, pull requests, issues and GitHub Actions–compatible CI in one platform | Runners for GitHub Actions; you stay on GitHub ([source](https://docs.blacksmith.sh/introduction/quickstart)) | | Who runs it | You: you deploy your instance to your own Cloudflare account and pay Cloudflare for its usage | Blacksmith runs the runners; GitHub runs the rest | | Where your code lives | Your Diffinery instance | GitHub (github.com, Enterprise Server or Enterprise Cloud) | | Setup | Deploy your instance ([guide](https://diffinery.com/docs/self-hosting/deploy)), then import your repositories; workflows run as they are | Install the GitHub App, change `runs-on` to a Blacksmith label such as `blacksmith-2vcpu-ubuntu-2404` | | Personal repositories | Yes | No: GitHub organizations only ([source](https://docs.blacksmith.sh/introduction/quickstart)) | | Linux x64 runner sizes | 1/4, 1/2, 2 and 4 vCPU; 4 vCPU and 12 GiB by default, smaller sizes picked per job from its measured runs | 2, 4, 8, 16 and 32 vCPU ([source](https://docs.blacksmith.sh/blacksmith-runners/overview)) | | Arm, Windows, macOS | Self-hosted runners only | Arm, Windows (public beta) and macOS on Apple M4 ([source](https://docs.blacksmith.sh/blacksmith-runners/overview)) | | Machines | Cloudflare Containers on AMD EPYC hosts | "Modern gaming CPUs", in Firecracker microVMs ([source](https://docs.blacksmith.sh/blacksmith-runners/overview)) | | Linux x64 price | Free and open source (Apache-2.0); you pay Cloudflare for your instance's usage, with runner containers billed by the 10 ms while a job runs ([source](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026) | $0.004 per minute at 2 vCPU, rising with vCPU count; 3,000 free 2-vCPU minutes a month per organization ([pricing](https://www.blacksmith.sh/pricing), [free minutes](https://docs.blacksmith.sh/blacksmith-runners/overview)) | | Caches | Built-in cache actions that download in parallel ranges and extract while downloading | A colocated cache used by the official cache actions, plus Docker layer caching and sticky disks as paid add-ons ([source](https://www.blacksmith.sh/pricing)) | | Speed claim | Measured on our runners and published with methods: [Performance](https://diffinery.com/performance) | "2x faster than GitHub's runners" (Blacksmith's own claim, [source](https://www.blacksmith.sh/)) | | Regions | Cloudflare's network | Ashburn, Phoenix, Amsterdam and Frankfurt ([source](https://docs.blacksmith.sh/blacksmith-runners/overview)) | | Compliance | None: Diffinery is open-source software you run, not a certified service | SOC 2 Type 2 ([source](https://www.blacksmith.sh/security)) | | AI agents | Agent accounts with server-enforced guardrails, an MCP server, sandboxes, agent tasks and agent review | Agent products of its own; agents on GitHub work as they do there | | Pull requests, issues, code review | Built in | GitHub's | ## Where each one is the better fit **Blacksmith is the better fit when** your team is settled on GitHub, needs macOS, Windows, Arm or runners larger than 4 vCPUs, wants SOC 2 Type 2 today, wants faster CI without moving anything, or doesn't want to run any infrastructure itself. **Diffinery is the better fit when** you'd rather have one platform than GitHub plus a runner service and are happy to run it on your own Cloudflare account, your CI is Linux, you work with AI coding agents and want the forge itself to limit what they can do, or you want workflows, `gh`, your editor and your agents to move together. ## Frequently asked questions ### Can I use Blacksmith with Diffinery? No. Blacksmith runners connect to GitHub through its GitHub App. On Diffinery, jobs run on your instance's hosted runners in Cloudflare Containers or on your own machines with `diffinery runner`. ### Is Diffinery cheaper than Blacksmith? Diffinery itself is free and open source; you pay Cloudflare for what your instance uses, on the Workers Paid plan ("a minimum cost of $5 USD per month per account", plus usage above the included amounts; [source](https://developers.cloudflare.com/workers/platform/pricing/), checked October 25, 2026). That bill depends on your usage, so we don't quote a per-minute figure to compare. Blacksmith lists $0.004 per minute for a 2-vCPU Linux runner, against GitHub's $0.006, and runs the machines for you. Diffinery's default runner has 4 vCPUs. ### Which is faster? We haven't benchmarked Blacksmith and don't quote others' numbers as our own. Diffinery's measured stage times are on the [Performance](https://diffinery.com/performance) page; Blacksmith publishes its own claims on its website. --- # Diffinery vs Depot > Depot sells fast GitHub Actions runners, its own Depot CI engine and container builds. How it compares with Diffinery, with specs, prices and trade-offs. Source: https://diffinery.com/compare/depot (last updated 2026-10-25) Depot started with fast container builds and now sells drop-in runners for GitHub Actions, its own CI engine that runs GitHub Actions YAML (Depot CI), and Git hosting in beta (Depot Code). Diffinery is a git forge with pull requests, issues, GitHub Actions–compatible CI and AI agents in one platform. Depot is a service that runs everything for you; Diffinery is free, open-source software (Apache-2.0) that you deploy to your own Cloudflare account, with no hosted service (see [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy) and the [source code](https://diffinery.com/codician/diffinery)). Depot facts here are from its own website and documentation, checked on October 16, 2026, and linked below. ## In short - **Choose Depot** if you want faster CI and container builds while staying on GitHub, need large, Arm, Windows or macOS runners, want SOC 2 Type 2 today, or want a service that runs the machines for you. - **Choose Diffinery** if you want code hosting, pull request review and CI in one product, and AI agents held to guardrails by the forge itself, and you're happy to run your own instance on Cloudflare. ## Side by side | | Diffinery | Depot | | --- | --- | --- | | Who runs it | You: you deploy your instance to your own Cloudflare account and pay Cloudflare for its usage | Depot | | What it is | Git hosting, pull requests, issues, releases, a container registry and GitHub Actions–compatible CI | GitHub Actions runners, Depot CI (generally available since March 2026), container builds, a registry, and Depot Code (beta) ([runners](https://depot.dev/docs/github-actions/overview), [Depot CI](https://depot.dev/changelog/2026-03-24-depot-ci-now-available)) | | Git hosting and pull requests | Yes, with reviews, required checks, auto-merge and a merge queue | Depot Code, in beta: repositories or GitHub mirrors that trigger CI on push; Depot says a code review UI is in progress ([source](https://depot.dev/docs/code/overview)) | | Runners for GitHub-hosted repositories | No (Diffinery runs its own repositories' workflows) | Yes, for repositories owned by GitHub organizations, with a `runs-on: depot-ubuntu-24.04` label ([source](https://depot.dev/docs/github-actions/overview)) | | Linux x64 runner sizes | 1/4, 1/2, 2 and 4 vCPU; 4 vCPU and 12 GiB by default | 2 to 64 vCPU, 8 to 256 GB, on AMD EPYC Genoa ([source](https://depot.dev/docs/github-actions/runner-types)) | | Arm, Windows, macOS | Self-hosted runners only | Arm (Graviton4) and Windows; macOS on the Startup and Business plans ([source](https://depot.dev/docs/github-actions/runner-types)) | | Linux x64 price | Free and open source (Apache-2.0); you pay Cloudflare for your instance's usage, with runner containers billed by the 10 ms while a job runs ([source](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026) | $0.006 per minute at 2 vCPU, tracked per second; plans from $20 a month with 2,000 runner minutes included ([source](https://depot.dev/pricing)) | | Free use | The software is free; your Cloudflare account needs the Workers Paid plan, "a minimum cost of $5 USD per month per account" ([source](https://developers.cloudflare.com/workers/platform/pricing/), checked October 25, 2026) | A 7-day trial ([source](https://depot.dev/pricing)) | | Caches | Built-in cache actions with parallel downloads | Accelerated Actions cache with no configuration, and remote BuildKit builders for Docker ([source](https://depot.dev/docs/github-actions/overview)) | | Speed claim | Measured on our runners and published with methods: [Performance](https://diffinery.com/performance) | "Up to 3x faster than a GitHub-hosted runner" and "10x faster caching" (Depot's own claims, [source](https://depot.dev/docs/github-actions/overview)) | | Compliance | None: Diffinery is open-source software you run, not a certified service | SOC 2 Type 2 ([source](https://depot.dev/security)) | | AI agents | Agent accounts with server-enforced guardrails, an MCP server, sandboxes, agent tasks and agent review | Agent sandboxes; agents on GitHub work as they do there | ## Where each one is the better fit **Depot is the better fit when** container image builds are your bottleneck, you need runners bigger than 4 vCPUs or on macOS, Windows or Arm, you want to keep GitHub as your forge and speed up CI around it, or you don't want to run any infrastructure yourself. **Diffinery is the better fit when** you want one place for code, review and CI with a mature pull request workflow, when your CI is Linux, and when AI agents do a growing share of your work and you want the forge to enforce what they can and can't do. You run Diffinery yourself, on your own Cloudflare account. ## Frequently asked questions ### Can Depot runners run Diffinery workflows? No. Depot's runners connect to GitHub organizations, and Depot CI runs workflows for GitHub and Depot Code repositories. On Diffinery, jobs run on your instance's hosted runners in Cloudflare Containers or on your own machines with `diffinery runner`. ### Can I build container images on Diffinery? Yes. Hosted runners include Docker with Buildx, and images push to your instance's own registry at `//`. See [Docker in workflows](https://diffinery.com/docs/actions/docker) and [Container registry](https://diffinery.com/docs/packages/container-registry). ### Which is faster? We haven't benchmarked Depot and don't quote others' numbers as our own. Diffinery's measured stage times are on the [Performance](https://diffinery.com/performance) page; Depot publishes its own claims in its documentation. --- # Diffinery vs CircleCI > CircleCI runs CI for code on GitHub, GitLab or Bitbucket. Diffinery hosts the code and runs GitHub Actions workflows. Formats, runners, prices, trade-offs. Source: https://diffinery.com/compare/circleci (last updated 2026-10-25) CircleCI is a hosted CI/CD service: your code stays on GitHub, GitLab or Bitbucket, and CircleCI runs the pipelines you define in `.circleci/config.yml`. It also sells a self-hosted edition, CircleCI Server, and since September 2026 it has been previewing support for running GitHub Actions workflow files. Diffinery is a git forge with CI built in: it hosts your repositories, pull requests and issues, and runs GitHub Actions workflows as they are. It is free, open-source software (Apache-2.0) that you deploy to your own Cloudflare account, with no hosted service (see [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy) and the [source code](https://diffinery.com/codician/diffinery)). CircleCI facts here are from its own website and documentation, checked on October 25, 2026, and linked below. ## In short - **The biggest difference is what each one replaces.** CircleCI replaces only your CI and works next to the Git host you already have. Diffinery replaces the Git host and the CI together. - **Choose CircleCI** if you want to keep your code where it is, need hosted Arm, Windows, macOS or GPU machines, want machines larger than 4 vCPUs, want SOC 2 Type 2 and FedRAMP today, want a self-hosted edition on your own Kubernetes cluster, or want a service that CircleCI runs for you. - **Choose Diffinery** if you want code hosting, review and CI in one product, workflows written as GitHub Actions YAML (supported as the main format, not in preview), and AI agents held to guardrails by the forge itself, and you're happy to run your own instance on Cloudflare. ## Side by side | | Diffinery | CircleCI | | --- | --- | --- | | What it is | Git hosting, pull requests, issues, releases, a container registry and GitHub Actions–compatible CI in one platform | A CI/CD service that connects to your Git host, with a self-hosted edition ([source](https://circleci.com/pricing/server/)) | | Who runs it | You: you deploy your instance to your own Cloudflare account and pay Cloudflare for its usage | CircleCI, or you with CircleCI Server | | Where your code lives | Your Diffinery instance | GitHub.com, GitHub Enterprise Cloud and Server, GitLab (SaaS and self-managed), Bitbucket Cloud, or Cursor Origin (beta) ([source](https://circleci.com/docs/guides/integration/version-control-system-integration-overview/)) | | Pipeline format | GitHub Actions YAML in `.github/workflows/` | `.circleci/config.yml` ([source](https://circleci.com/docs/reference/configuration-reference/)), with reusable configuration packages called orbs ([source](https://circleci.com/docs/orb-intro/)) | | GitHub Actions workflow files | The main format; every difference is listed in [Compatibility](https://diffinery.com/docs/actions/compatibility) | In preview: GitHub repositories only, Linux only, and some keys are ignored, such as the `branches`, `paths` and `types` filters under `on:`, `schedule` and `concurrency` ([source](https://circleci.com/docs/guides/orchestrate/use-a-github-actions-workflow-file-as-your-pipeline-configuration/)) | | Linux x64 machine sizes | 1/4, 1/2, 2 and 4 vCPU; 4 vCPU and 12 GiB by default, smaller sizes picked per job from its measured runs | Docker from Small (1 CPU, 2 GB) to X-large (8 CPU, 16 GB), and Linux VMs from Medium (2 CPU, 7.5 GB) ([source](https://circleci.com/pricing/price-list/)); 2X-large and larger classes on the Scale plan ([source](https://circleci.com/pricing/)) | | Arm, Windows, macOS, GPU | Self-hosted runners only | Arm, Windows and macOS on every plan; GPU on the Scale plan ([source](https://circleci.com/pricing/)) | | Linux x64 price | Free and open source (Apache-2.0); you pay Cloudflare for your instance's usage, with runner containers billed by the 10 ms while a job runs ([source](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026) | Credits at $0.0006 each, billed by the second ([source](https://circleci.com/docs/guides/plans-pricing/credits/)). A 2-CPU Docker Medium uses 10 credits a minute ([source](https://circleci.com/pricing/price-list/)), which works out to $0.006 a minute | | Plans | None. Your Cloudflare account needs the Workers Paid plan, "a minimum cost of $5 USD per month per account", plus usage above the included amounts ([source](https://developers.cloudflare.com/workers/platform/pricing/), checked October 25, 2026) | Free: 30,000 credits a month and up to 5 active users. Performance: from $15 a month with 5 active users, $15 a month for each extra user. Scale: custom, billed annually ([source](https://circleci.com/pricing/)) | | Self-hosted runners | `diffinery runner`, on any machine | On every plan: 5 concurrent tasks on Free, 20 on Performance, unlimited on Scale ([source](https://circleci.com/pricing/)) | | Self-hosted edition | Diffinery is always self-deployed: open source (Apache-2.0), on your own Cloudflare account ([guide](https://diffinery.com/docs/self-hosting/deploy)). It doesn't run on your own servers or Kubernetes | CircleCI Server, on GKE, EKS or your own Kubernetes, for GitHub Enterprise Cloud and Server only ([source](https://circleci.com/pricing/server/)) | | Compliance | None: Diffinery is open-source software you run, not a certified service | SOC 2 Type 2 and FedRAMP LI-SaaS, among others listed on its Trust Center ([source](https://trust.circleci.com/)) | | MCP server | Built in at `/mcp` on your instance: read code, commit, open, review and merge pull requests, follow CI and run commands in sandboxes | Hosted at `https://mcp.circleci.com/v1/mcp`: inspect runs, jobs, logs, artifacts and test results, and rerun or cancel workflows ([source](https://circleci.com/docs/guides/toolkit/circleci-mcp-overview/)) | | AI agents | Agent accounts with server-enforced guardrails, sandboxes, agent tasks and agent review | Agents on your Git host work as they do there | | Pull requests, issues, code review | Built in | Your Git host's | ## Where each one is the better fit **CircleCI is the better fit when** you want to keep GitHub, GitLab or Bitbucket and change only your CI, when you build for macOS, Windows, Arm or GPUs on hosted machines, when your builds need more than 4 vCPUs, when you need SOC 2 Type 2 or FedRAMP paperwork today, when you need to run CI inside your own network with CircleCI Server, or when you'd rather not run any infrastructure yourself. **Diffinery is the better fit when** you'd rather have one platform than a Git host plus a CI service and are happy to run it on your own Cloudflare account, your CI is Linux, you want to write workflows in the GitHub Actions format and use actions from GitHub as they are, and you work with AI coding agents and want the forge to limit what they can do. ## Moving from CircleCI Deploy your own instance first ([guide](https://diffinery.com/docs/self-hosting/deploy)). Diffinery's importer reads from GitHub. If your code is on GitHub, it brings over each repository with its history, issues, pull requests, reviews and releases; see [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github). From GitLab or Bitbucket, push branches and tags with plain Git; see [Move with plain Git](https://diffinery.com/docs/migrate-from-github#move-with-plain-git). Then rewrite each `.circleci/config.yml` as workflows in `.github/workflows/`, and check them with `diffinery workflow validate`. ## Frequently asked questions ### Is Diffinery a CircleCI alternative? Yes, if you're willing to move your repositories as well. Diffinery's CI runs on its own repositories, so it replaces CircleCI and your Git host together. If you want to keep your current Git host and only change CI, CircleCI or a GitHub Actions runner service is the closer fit; see [GitHub Actions alternatives, compared](https://diffinery.com/compare). ### Can I run my CircleCI config on Diffinery? No. Diffinery runs GitHub Actions workflows, not `.circleci/config.yml`, and CircleCI orbs don't run on it. Teams moving from CircleCI rewrite their pipelines as workflows, usually replacing each orb with a GitHub action that does the same job. ### Can CircleCI run GitHub Actions workflows? In preview. CircleCI announced on September 22, 2026 that it can run existing GitHub Actions workflow files on its own machines ([source](https://circleci.com/blog/github-actions-alternative-run-actions-on-circleci/)). Its documentation says the preview works with GitHub repositories, runs Linux jobs only, doesn't apply the filters under `on:` or `schedule`, and gives `concurrency` no effect ([source](https://circleci.com/docs/guides/orchestrate/use-a-github-actions-workflow-file-as-your-pipeline-configuration/)). On Diffinery, GitHub Actions is the native format. ### Can I use CircleCI with Diffinery? Not today. CircleCI connects to GitHub, GitLab, Bitbucket Cloud and Cursor Origin, and Diffinery isn't one of them. On Diffinery, jobs run on your instance's hosted runners in Cloudflare Containers or on your own machines with `diffinery runner`. ### Is Diffinery cheaper than CircleCI? Diffinery itself is free and open source; you pay Cloudflare for what your instance uses, which depends on your usage, so we don't quote a per-minute figure to compare. CircleCI's Free plan includes 30,000 credits a month, and a 2-CPU Docker job uses 10 credits a minute, so about 3,000 minutes of that size. Paid credits cost $0.0006 each, and CircleCI runs the machines for you. Diffinery's default runner has 4 vCPUs and 12 GiB of memory, against 2 CPUs and 4 GB on CircleCI's Docker Medium. ### Which is faster, Diffinery or CircleCI? We haven't benchmarked CircleCI and don't quote others' numbers as our own. Diffinery's measured stage times are on the [Performance](https://diffinery.com/performance) page. CircleCI says sampled builds in its GitHub Actions preview ran "40% faster" than on GitHub Actions (CircleCI's own claim, [source](https://circleci.com/blog/github-actions-alternative-run-actions-on-circleci/)). --- # Diffinery vs Buildkite > Buildkite orchestrates CI on agents you run or it hosts, for code on GitHub, GitLab or Bitbucket. Diffinery hosts code and runs GitHub Actions workflows. Source: https://diffinery.com/compare/buildkite (last updated 2026-10-25) Buildkite Pipelines is a CI/CD service with a hybrid design: Buildkite runs the control plane (the web interface, APIs and scheduling), and the jobs run on agents, either on your own machines or on agents Buildkite hosts. Your code stays on GitHub, GitLab or Bitbucket. Diffinery is a git forge with CI built in: it hosts your repositories, pull requests and issues, and runs GitHub Actions workflows as they are on its own runners. It is free, open-source software (Apache-2.0) that you deploy to your own Cloudflare account, with no hosted service (see [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy) and the [source code](https://diffinery.com/codician/diffinery)). Buildkite facts here are from its own website and documentation, checked on October 25, 2026, and linked below. ## In short - **The biggest difference is who runs the machines.** Buildkite is built around agents on your own infrastructure, which keeps your source code and secrets inside your network. Diffinery runs every job on hosted runners that your instance starts in Cloudflare Containers on your own Cloudflare account, unless you add self-hosted ones; there are no build machines to manage. - **Choose Buildkite** if you want builds on your own fleet at large scale, need hosted macOS or machines larger than 4 vCPUs, want pipelines generated by code while a build runs, want SOC 2 Type II today, or want to keep your current Git host. - **Choose Diffinery** if you don't want to manage build machines or a separate CI service, are happy to run your own instance on Cloudflare, want code hosting, review and CI in one product, write workflows as GitHub Actions YAML, and want AI agents held to guardrails by the forge itself. ## Side by side | | Diffinery | Buildkite | | --- | --- | --- | | What it is | Git hosting, pull requests, issues, releases, a container registry and GitHub Actions–compatible CI in one platform | A CI/CD control plane run by Buildkite, with the jobs on agents you run or on Buildkite hosted agents ([source](https://buildkite.com/docs/pipelines/architecture)) | | Who runs it | You: you deploy your instance to your own Cloudflare account and pay Cloudflare for its usage | Buildkite runs the control plane; you or Buildkite run the agents | | Where your code lives | Your Diffinery instance | GitHub, GitLab (including self-managed) or Bitbucket ([GitHub](https://buildkite.com/docs/pipelines/source-control/github), [GitLab](https://buildkite.com/docs/pipelines/source-control/gitlab), [Bitbucket](https://buildkite.com/docs/integrations/bitbucket)) | | Where jobs run | Your instance's hosted runners in Cloudflare Containers, or your own machines with `diffinery runner` | Your own machines, on premises or in your cloud, or Buildkite hosted agents. With your own agents, Buildkite says "source code and secrets, remain within your environment and are not seen by the Buildkite Platform" ([source](https://buildkite.com/docs/pipelines/architecture)) | | Pipeline format | GitHub Actions YAML in `.github/workflows/` | Buildkite YAML, usually `.buildkite/pipeline.yml`, uploaded by an agent at the start of a build; steps can be added while a build runs ([source](https://buildkite.com/docs/pipelines/configure/defining-steps)), and plugins hook into the job lifecycle ([source](https://buildkite.com/docs/pipelines/integrations/plugins)) | | GitHub Actions workflow files | The main format; every difference is listed in [Compatibility](https://diffinery.com/docs/actions/compatibility) | In public preview, as native Buildkite jobs. `pull_request_target` is "intentionally unsupported", `workflow_run` and `repository_dispatch` aren't supported yet, and GitHub-hosted runner images aren't reproduced ([source](https://buildkite.com/docs/pipelines/migration/run-github-actions-workflows)) | | Hosted Linux x64 sizes | 1/4, 1/2, 2 and 4 vCPU; 4 vCPU and 12 GiB by default | Small (2 vCPU, 4 GB) on every plan; Medium (4 vCPU, 16 GB) and Large (8 vCPU, 32 GB) on paid plans; up to 64 vCPU and 256 GB, and Arm, on Enterprise ([source](https://buildkite.com/docs/agent/buildkite-hosted/linux)) | | Hosted macOS and Windows | Not available; use self-hosted runners | macOS on Apple M4 ([source](https://buildkite.com/pricing/)); Windows hosted agents in private preview ([source](https://buildkite.com/docs/pipelines/migration/run-github-actions-workflows)) | | Hosted Linux price | Free and open source (Apache-2.0); you pay Cloudflare for your instance's usage, with runner containers billed by the 10 ms while a job runs ([source](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026) | $0.004 per vCPU minute, so $0.008 a minute for Small (2 vCPU), metered to the second ([source](https://buildkite.com/pricing/)) | | Plans | None. Your Cloudflare account needs the Workers Paid plan, "a minimum cost of $5 USD per month per account", plus usage above the included amounts ([source](https://developers.cloudflare.com/workers/platform/pricing/), checked October 25, 2026) | Free: up to 5 users, 10 concurrent jobs and 2,000 Linux vCPU minutes a month. Pro: $30 per active user a month, 4,000 Linux vCPU minutes, 10 self-hosted agents included and $3.50 a month for each one after. Enterprise: custom ([source](https://buildkite.com/pricing/)) | | Longest job on hosted machines | 6 hours | 8 hours on hosted Linux agents ([source](https://buildkite.com/docs/agent/buildkite-hosted/linux)) | | Compliance | None: Diffinery is open-source software you run, not a certified service | SOC 2 Type II ([source](https://buildkite.com/about/security/)) | | MCP server | Built in at `/mcp` on your instance: read code, commit, open, review and merge pull requests, follow CI and run commands in sandboxes | Hosted at `https://mcp.buildkite.com/mcp`, with data from pipelines, builds, jobs and Test Engine, and write actions such as retrying jobs ([source](https://buildkite.com/docs/apis/mcp-server)) | | AI agents | Agent accounts with server-enforced guardrails, sandboxes, agent tasks and agent review | Agents on your Git host work as they do there | | Pull requests, issues, code review | Built in | Your Git host's | ## Where each one is the better fit **Buildkite is the better fit when** you already run, or want to run, your own build machines, for example for security, special hardware or cost at very high volume; when source code and secrets must stay inside your network; when you need hosted macOS or machines larger than 4 vCPUs; when your pipelines are big enough that generating steps from code pays off; or when you want to keep GitHub, GitLab or Bitbucket. Buildkite's hosted agents and control plane are also run for you, where a Diffinery instance is yours to deploy and update. **Diffinery is the better fit when** you want CI without managing any build machines, one platform for code, review and CI, workflows in the GitHub Actions format with actions from GitHub as they are, and a forge that enforces what AI agents can and can't do, and you're happy to run that forge on your own Cloudflare account. Your CI should be Linux, or you should be happy to add self-hosted runners for the rest. ## Moving from Buildkite Deploy your own instance first ([guide](https://diffinery.com/docs/self-hosting/deploy)). Diffinery's importer reads from GitHub. If your code is on GitHub, it brings over each repository with its history, issues, pull requests, reviews and releases; see [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github). From GitLab or Bitbucket, push branches and tags with plain Git; see [Move with plain Git](https://diffinery.com/docs/migrate-from-github#move-with-plain-git). Then rewrite each Buildkite pipeline as workflows in `.github/workflows/`. Jobs that need your own hardware can keep it: register those machines with `diffinery runner` and target them with `runs-on: [self-hosted, ...]`. See [Self-hosted runners](https://diffinery.com/docs/actions/runners#self-hosted-runners). ## Frequently asked questions ### Is Diffinery a Buildkite alternative? Yes, if you're willing to move your repositories as well. Diffinery's CI runs on its own repositories, so it replaces Buildkite and your Git host together. Like Buildkite, it can run jobs on your own machines, with `diffinery runner`; unlike Buildkite, it also runs every Linux job on hosted runners in your Cloudflare account by default. ### Can I run my Buildkite pipelines on Diffinery? No. Diffinery runs GitHub Actions workflows, not Buildkite pipeline YAML, and Buildkite plugins don't run on it. Teams moving from Buildkite rewrite their pipelines as workflows. Pipelines that generate their steps at build time map most closely to GitHub Actions matrices whose values come from an earlier job's outputs. ### Can Buildkite run GitHub Actions workflows? In public preview. Buildkite's GitHub Actions Compatibility runs supported workflows from `.github/workflows/` as Buildkite jobs, with limits: no `pull_request_target`, no `workflow_run` or `repository_dispatch` yet, and no reproduction of GitHub's runner images ([source](https://buildkite.com/docs/pipelines/migration/run-github-actions-workflows)). On Diffinery, GitHub Actions is the native format. ### Can I use Buildkite with Diffinery? Buildkite's documented source control integrations are GitHub, GitLab and Bitbucket, and Diffinery isn't one of them. On Diffinery, jobs run on your instance's hosted runners in Cloudflare Containers or on your own machines with `diffinery runner`. ### Is Diffinery cheaper than Buildkite? Diffinery itself is free and open source; you pay Cloudflare for what your instance uses, which depends on your usage, so we don't quote a per-minute figure to compare. Buildkite charges per active user on Pro ($30 a month) plus hosted minutes at $0.004 per vCPU minute, or $3.50 a month per self-hosted agent after the first 10; with your own agents you also pay for the machines. ### Which is faster, Diffinery or Buildkite? We haven't benchmarked Buildkite and don't quote others' numbers as our own. With self-hosted agents, Buildkite's speed depends mostly on the machines you give it. Diffinery's measured stage times are on the [Performance](https://diffinery.com/performance) page. --- # Diffinery vs Bitbucket and Bitbucket Pipelines > How Diffinery compares with Bitbucket Cloud and Bitbucket Pipelines on CI format, build minutes, runner sizes, prices, Jira, AI agents and self-managed options. Source: https://diffinery.com/compare/bitbucket (last updated 2026-10-25) Bitbucket is Atlassian's Git hosting, with Bitbucket Pipelines for CI/CD built in and close ties to Jira. It comes as Bitbucket Cloud and as Bitbucket Data Center, Atlassian's self-managed edition. Diffinery is a git forge with GitHub Actions–compatible CI built in, designed for teams of people and AI agents. It is free, open-source software (Apache-2.0) that you deploy to your own Cloudflare account, with no hosted service (see [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy) and the [source code](https://diffinery.com/codician/diffinery)). Bitbucket facts here are from Atlassian's own website and documentation, checked on October 25, 2026, and linked below. ## In short - **The biggest difference is the CI format.** Bitbucket Pipelines uses `bitbucket-pipelines.yml`. Diffinery runs GitHub Actions workflows (`.github/workflows/*.yml`) as they are, so it suits teams coming from GitHub, or teams that want the GitHub Actions ecosystem of reusable actions. - **Choose Bitbucket** if your team plans its work in Jira and uses other Atlassian products, needs hosted Arm builds or build steps larger than 4 vCPUs, needs to run the forge on its own servers, or wants a service that Atlassian runs for you. - **Choose Diffinery** if you want GitHub Actions compatibility, 4-vCPU runners by default, a forge built around AI agents with server-enforced guardrails, and push protection on every repository, and you're happy to run your own instance on Cloudflare. ## Side by side | | Diffinery | Bitbucket Cloud | | --- | --- | --- | | Who runs it | You: you deploy your instance to your own Cloudflare account and pay Cloudflare for its usage | Atlassian | | What it is | Git hosting, pull requests, issues, releases, a container registry and GitHub Actions–compatible CI | Git hosting with Bitbucket Pipelines, connected to Jira and Atlassian's Rovo AI ([source](https://www.atlassian.com/software/bitbucket)) | | Pipeline format | GitHub Actions YAML in `.github/workflows/` | `bitbucket-pipelines.yml` at the root of the repository ([source](https://support.atlassian.com/bitbucket-cloud/docs/get-started-with-bitbucket-pipelines/)), extended with Pipes for third-party tools ([source](https://www.atlassian.com/software/bitbucket/features/pipelines)) | | Default hosted machine | 4 vCPU, 12 GiB memory, 20 GB disk | Size 1x, with 4 GB of memory ([source](https://support.atlassian.com/bitbucket-cloud/docs/global-options/)) | | Other hosted sizes | 2, 1/2 and 1/4 vCPU, picked per job from its measured runs | 2x (8 GB) up to 32x (128 GB); 4x and larger on the Standard and Premium plans. A 2x step uses twice the build minutes of a 1x step, and so on ([source](https://support.atlassian.com/bitbucket-cloud/docs/global-options/)) | | Hosted Arm | No; use self-hosted runners | Yes, on the Standard and Premium plans ([source](https://www.atlassian.com/blog/development/announcing-arm-builds-in-cloud-for-bitbucket-pipelines)) | | Self-hosted runners | `diffinery runner`, on any machine | Linux Docker, Linux Shell, Windows and macOS, plus Linux Docker on Arm64 in beta ([source](https://support.atlassian.com/bitbucket-cloud/kb/bitbucket-runners-comparison/)) | | Included CI minutes | Nothing to buy. By default each account gets 3,000 hosted minutes a month, a quota your instance's administrators set ([Configuration](https://diffinery.com/docs/self-hosting/configuration)) | 50 build minutes a month on Free, 2,500 on Standard, 3,500 on Premium ([Free](https://www.atlassian.com/software/bitbucket/pricing), [Standard and Premium](https://www.atlassian.com/licensing/bitbucket)) | | Extra minutes | None to buy; you pay Cloudflare for your instance's usage, with runner containers billed by the 10 ms while a job runs ([source](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026) | $10 per 1,000 minutes ([source](https://www.atlassian.com/licensing/bitbucket)); allowances are pooled across an organization from October 26, 2026 on monthly plans ([source](https://support.atlassian.com/bitbucket-cloud/docs/manage-your-plan-and-billing/)) | | Per-user price | None: free and open source (Apache-2.0). Your Cloudflare account needs the Workers Paid plan, "a minimum cost of $5 USD per month per account", plus usage above the included amounts ([source](https://developers.cloudflare.com/workers/platform/pricing/), checked October 25, 2026) | Free for up to 5 users; Standard $3.65 and Premium $8 per user per month ([source](https://www.atlassian.com/software/bitbucket/pricing)) | | Longest step | 6 hours | 120 minutes by default, up to 720 with `max-time` ([source](https://support.atlassian.com/bitbucket-cloud/docs/global-options/)) | | Security controls | Passkeys only, push protection on every repository, branch protection, agent guardrails, append-only audit log | Premium adds enforced merge checks, IP allowlisting, deployment permissions and required two-step verification ([source](https://www.atlassian.com/software/bitbucket/pricing)) | | Compliance | None: Diffinery is open-source software you run, not a certified service | Bitbucket Cloud is listed among the products on Atlassian's SOC 2 page ([source](https://www.atlassian.com/trust/compliance/resources/soc2)) | | Self-managed edition | Diffinery is always self-deployed: open source (Apache-2.0), on your own Cloudflare account ([guide](https://diffinery.com/docs/self-hosting/deploy)). There's no version for your own servers | Bitbucket Data Center ([source](https://www.atlassian.com/software/bitbucket/pricing)) | | MCP server | Built in at `/mcp` on your instance | Through the Atlassian Rovo MCP Server since April 2026: repositories, pull requests, commits, branches, pipelines and deployments, for workspaces linked to an Atlassian organization ([source](https://www.atlassian.com/blog/bitbucket/the-atlassian-rovo-mcp-server-now-supports-bitbucket-cloud)) | | AI agents | Agent accounts with their own tokens and server-enforced guardrails; [agent tasks](https://diffinery.com/docs/agents/tasks) and [agent review](https://diffinery.com/docs/agents/review) with your own model key | Rovo Dev, which Atlassian says can "turn Jira items into code, review code and more" ([source](https://www.atlassian.com/software/bitbucket)) | | Planning | Issues with labels, milestones and assignees | Connected to Jira ([source](https://www.atlassian.com/software/bitbucket)) | ## Where each one is the better fit **Bitbucket is the better fit when** your company runs on Jira and Confluence and wants code linked to Jira work items, when you need hosted Arm builds or build steps with more than 4 vCPUs, when you need a self-managed edition in your own data center, or when you'd rather not run any infrastructure yourself. **Diffinery is the better fit when** you want to write CI in the GitHub Actions format and use actions from GitHub as they are, when faster default runners matter for your Linux builds, and when AI agents write a growing share of your code and you want the forge to enforce what they can and can't do. You run Diffinery yourself, on your own Cloudflare account. ## Moving from Bitbucket Deploy your own instance first ([guide](https://diffinery.com/docs/self-hosting/deploy)). Diffinery's importer reads from GitHub. From Bitbucket, push your branches and tags with plain Git (see [Move with plain Git](https://diffinery.com/docs/migrate-from-github#move-with-plain-git)), then rewrite `bitbucket-pipelines.yml` as workflows in `.github/workflows/` and check them with `diffinery workflow validate`. Issues and pull requests don't come across this way. Steps that need Windows or macOS keep running on your own machines through [self-hosted runners](https://diffinery.com/docs/actions/runners#self-hosted-runners). ## Frequently asked questions ### Is Diffinery a Bitbucket alternative? Yes. Like Bitbucket Cloud, Diffinery hosts Git repositories with pull requests, reviews, branch protection and built-in CI. It doesn't have Bitbucket's Jira integration, hosted Arm builds, build steps larger than 4 vCPUs or a version for your own servers, and Bitbucket Cloud is a service Atlassian runs for you, where Diffinery is software you run on your own Cloudflare account. ### Does Diffinery run bitbucket-pipelines.yml? No. Diffinery runs GitHub Actions workflows. Teams moving from Bitbucket Pipelines rewrite their pipelines as workflows in `.github/workflows/`, usually replacing each Pipe with a GitHub action that does the same job. ### Is Diffinery cheaper than Bitbucket? Diffinery itself is free and open source, with no per-user price; you pay Cloudflare for what your instance uses, which depends on your usage, so we don't quote a figure to compare. Bitbucket Cloud lists $3.65 per user per month on Standard with 2,500 build minutes, $8 on Premium with 3,500, and $10 for each extra 1,000 minutes. A build minute on Bitbucket is counted at the step's size, so a minute on a 2x step uses two. ### Can I use Jira with Diffinery? Diffinery has no built-in Jira integration. It sends GitHub-compatible [webhooks](https://diffinery.com/docs/repositories/webhooks) and has a GitHub-style REST API, so you can connect your own automation to pushes, pull requests and CI results. ### Is Bitbucket Data Center being discontinued? Not according to Atlassian. Its Data Center end-of-life page says that, unlike its other Data Center products, Bitbucket and Bamboo Data Center "will not end of life", and that existing customers can renew to a Bitbucket Hybrid License that covers Data Center and Bitbucket Cloud ([source](https://www.atlassian.com/licensing/data-center-end-of-life)). --- # Diffinery vs Gitea and Forgejo > Gitea, Forgejo and Diffinery are all open-source forges you run yourself. Gitea and Forgejo run on your servers; Diffinery on your Cloudflare account. Source: https://diffinery.com/compare/gitea (last updated 2026-10-25) Gitea and Forgejo are open-source, self-hosted git forges. Forgejo was created from Gitea in October 2022 ([source](https://forgejo.org/compare-to-gitea/)) and is developed under Codeberg e.V., a non-profit, which also runs the public forge Codeberg.org on Forgejo ([source](https://docs.codeberg.org/getting-started/what-is-codeberg/)). Both have built-in CI whose workflow files look like GitHub Actions (Gitea Actions and Forgejo Actions), with jobs run by runners you install. Diffinery is also open source (Apache-2.0) and also something you run yourself, but on your own Cloudflare account rather than on your own servers: it runs GitHub Actions workflows on runners that your instance starts in Cloudflare Containers (see [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy) and the [source code](https://diffinery.com/codician/diffinery)). Gitea, Forgejo and Codeberg facts here are from their own websites and documentation, checked on October 25, 2026, and linked below. ## In short - **The biggest difference is where it runs.** All three are open-source forges you run yourself. Gitea and Forgejo are software you install and operate on your own servers, along with the runners for their CI (unless you buy Gitea Cloud, which runs both for you). Diffinery runs only on Cloudflare: you deploy it to your own Cloudflare account, with no servers or runner machines to manage, but your code lives on Cloudflare's infrastructure rather than on hardware you control, and there's no version for your own machines. - **Choose Gitea or Forgejo** if your code has to stay on servers you control, you don't want to depend on one cloud provider, you want a forge someone runs for you (Gitea Cloud, or Codeberg for free software), or you want a forge with wikis and a package registry. Choose Forgejo if non-profit governance and a copyleft license matter to you. - **Choose Diffinery** if you want hosted runners with 4 vCPUs by default and documented GitHub Actions compatibility, no servers or runner machines to look after, and AI agents held to guardrails by the forge itself, and Cloudflare is an acceptable place for your code. ## Side by side | | Diffinery | Gitea | Forgejo | | --- | --- | --- | --- | | What it is | An open-source git forge with pull requests, issues, releases, a container registry and GitHub Actions–compatible CI, deployed to your own Cloudflare account | "A self-hosted DevOps platform", open source with commercial support from CommitGo ([source](https://about.gitea.com/)) | "A self-hosted lightweight software forge" ([source](https://forgejo.org/)) | | License | Apache-2.0 ([source](https://diffinery.com/codician/diffinery)) | MIT ([source](https://about.gitea.com/pricing/)) | GPL v3 or later from v9.0; MIT up to v8.0 ([source](https://forgejo.org/faq/)) | | Who develops it | The Diffinery project, in the open at [diffinery.com/codician/diffinery](https://diffinery.com/codician/diffinery), mirrored [on GitHub](https://github.com/codician-team/diffinery) | Gitea, led by CommitGo ([source](https://about.gitea.com/)) | A community under Codeberg e.V., a non-profit ([source](https://forgejo.org/)) | | Where it runs | Your own Cloudflare account and domain only ([guide](https://diffinery.com/docs/self-hosting/deploy)); not on your own servers, and there's no hosted service | Your own servers: builds for Linux, Windows, macOS and FreeBSD, with SQLite, MySQL or PostgreSQL ([source](https://docs.gitea.com/installation/install-from-binary)); or fully managed as Gitea Cloud ([source](https://about.gitea.com/products/cloud/)) | Your own servers; or Codeberg.org for free software projects ([source](https://docs.codeberg.org/getting-started/faq/)) | | CI | Diffinery Actions: GitHub Actions YAML from `.github/workflows/` | Gitea Actions, since Gitea 1.19: "similar and mostly compatible to GitHub Actions" ([source](https://docs.gitea.com/usage/actions/overview)), with workflows in `.gitea/workflows/` and off by default in each repository ([source](https://docs.gitea.com/usage/actions/quickstart)) | Forgejo Actions: "designed to be familiar to users of GitHub Actions" but "not designed to be compatible"; reads `.github/workflows/` when there's no `.forgejo/workflows/` ([source](https://forgejo.org/docs/latest/user/actions/overview/)) | | Known differences from GitHub Actions | Listed in [Compatibility](https://diffinery.com/docs/actions/compatibility) | `jobs..environment` is ignored, problem matchers and error annotations are ignored, and some `permissions` scopes aren't supported ([source](https://docs.gitea.com/usage/actions/comparison)) | A different default image (Debian with Node.js), some `github` context keys missing, `permissions` and `continue-on-error` on jobs ignored, and OIDC turned on with its own key ([source](https://forgejo.org/docs/latest/user/actions/github-actions/)) | | Hosted runners | Yes: your instance starts a fresh Ubuntu 24.04 container per job in Cloudflare Containers, 4 vCPU and 12 GiB by default, with no runner machines to install | Gitea Runner, which you install; on Gitea Cloud, runners start on demand ([runner](https://docs.gitea.com/usage/actions/overview), [Cloud](https://about.gitea.com/products/cloud/)) | Forgejo Runner, which you install ([source](https://forgejo.org/docs/latest/user/actions/overview/)). Codeberg offers hosted Forgejo Actions "in a limited fashion in open alpha", and a Woodpecker CI instance by request ([source](https://docs.codeberg.org/ci/)) | | Self-hosted runners | `diffinery runner`, on any machine | Yes | Yes | | Wikis and packages | No wikis; a container registry | Wikis, a package and container registry, Git LFS, push and pull mirrors and a merge queue, among others ([source](https://docs.gitea.com/installation/comparison)) | Wikis, a package and container registry, and repository mirrors, among others ([source](https://forgejo.org/docs/latest/user/)) | | Price | Free and open source. You pay Cloudflare for your instance's usage, on the Workers Paid plan: "a minimum cost of $5 USD per month per account", plus usage above the included amounts ([source](https://developers.cloudflare.com/workers/platform/pricing/), checked October 25, 2026) | Free to self-host; Gitea Enterprise is a per-user subscription with a 30-day trial ([source](https://about.gitea.com/pricing/)); Gitea Cloud has a 30-day trial and no published price ([source](https://about.gitea.com/products/cloud/)) | Free software. Codeberg hosts free software projects and doesn't offer private hosting for commercial projects ([source](https://docs.codeberg.org/getting-started/faq/)) | | MCP server | Built in at `/mcp` on your instance, with browser sign-in | An official MCP server, gitea-mcp, that you run next to your instance ([source](https://gitea.com/gitea/gitea-mcp)) | Not covered here | | AI agents | Agent accounts with server-enforced guardrails, sandboxes, agent tasks and agent review | Not covered here | Not covered here | ## Where each one is the better fit **Gitea or Forgejo is the better fit when** your code must stay on hardware you control, including inside a private network; when you don't want to depend on one cloud provider; when you'd rather have someone run the forge for you, with Gitea Cloud; when you need wikis or a package registry; or when you're happy to run a server and runners. Forgejo also suits teams that want a forge governed by a non-profit and licensed under the GPL. Codeberg suits free software projects that want a public forge run by a non-profit. **Diffinery is the better fit when** you want an open-source forge without operating servers or CI machines, are happy to run it on your own Cloudflare account, want hosted runners that run GitHub Actions workflows with every difference documented, want features such as push protection and agent guardrails on by default, and work with AI coding agents that should open pull requests rather than push to main. ## Moving from Gitea or Forgejo Deploy your own instance first ([guide](https://diffinery.com/docs/self-hosting/deploy)). Diffinery's importer reads from GitHub. From Gitea or Forgejo, push your branches and tags with plain Git; see [Move with plain Git](https://diffinery.com/docs/migrate-from-github#move-with-plain-git). Issues and pull requests don't come across this way. Diffinery reads workflows from `.github/workflows/` and `.diffinery/workflows/`, so move files from `.gitea/workflows/` or `.forgejo/workflows/` into one of them, and check them with `diffinery workflow validate`. ## Frequently asked questions ### Is Diffinery a Gitea or Forgejo alternative? Yes, if Cloudflare is an acceptable place for your code. Like Gitea and Forgejo, Diffinery is open source and you run it yourself. It covers Git hosting, pull requests, issues, releases, a container registry and CI, and your instance starts the runners for you in Cloudflare Containers. It isn't a replacement if you need to run the forge on your own servers or need wikis. ### Can I self-host Diffinery like Gitea or Forgejo? Yes, on your own Cloudflare account, but not on your own servers. Diffinery is open source (Apache-2.0) and runs on Cloudflare (Workers, Durable Objects, R2, D1, Workflows and Containers); see [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy) and [Architecture](https://diffinery.com/docs/self-hosting/architecture). Jobs can run on your own machines through [self-hosted runners](https://diffinery.com/docs/actions/runners#self-hosted-runners). ### Do Gitea Actions and Forgejo Actions workflows run on Diffinery? Most of their workflow syntax is GitHub Actions syntax, which Diffinery runs. Move the files into `.github/workflows/` or `.diffinery/workflows/`, and check anything specific to Gitea or Forgejo, such as Forgejo's `enable-openid-connect` key for OIDC (on Diffinery, use `permissions: id-token: write`, as on GitHub) or `runs-on` labels for runners you registered there. Every difference from GitHub is listed in [Compatibility with GitHub Actions](https://diffinery.com/docs/actions/compatibility). ### Are Gitea Actions compatible with GitHub Actions? Gitea describes Gitea Actions as "similar and mostly compatible to GitHub Actions" and lists the differences in its documentation ([source](https://docs.gitea.com/usage/actions/comparison)). Forgejo says Forgejo Actions is "designed to be familiar to users of GitHub Actions" but "not designed to be compatible" ([source](https://forgejo.org/docs/latest/user/actions/overview/)). ### Can I host a company's private code on Codeberg? Codeberg's FAQ says it "does not offer private hosting services" for commercial projects and points to self-hosting Forgejo instead ([source](https://docs.codeberg.org/getting-started/faq/)). ### Is Gitea or Forgejo cheaper than Diffinery? All three are free, open-source software. With Gitea and Forgejo you pay for the servers and runners and the time to run them; Gitea Enterprise and Gitea Cloud are paid. With Diffinery you pay Cloudflare for what your instance uses: the Workers Paid plan, "a minimum cost of $5 USD per month per account", plus usage above the included amounts ([source](https://developers.cloudflare.com/workers/platform/pricing/), checked October 25, 2026), and runner containers billed by the 10 ms while a job runs ([source](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026). Which costs less depends on your usage. --- # About Diffinery > Why Diffinery exists, why it's open source, how it's built, how we check the claims on this site, and how to reach us. Source: https://diffinery.com/about (last updated 2026-10-25) Diffinery is a git forge and CI platform for teams where AI agents write a growing share of the code. Agents do the work through Git, pull requests and CI like everyone else; people see what the agents did, approve what needs them and follow the whole process. Diffinery runs entirely on Cloudflare, and it's open source under the Apache License 2.0: you deploy it to your own Cloudflare account and run it yourself. ## Why we built it GitHub was designed for people. Agents on GitHub borrow a person's token, their pull requests look like anyone else's, and the only limits on them are the ones a team remembers to configure. We wanted a forge where an agent is an account of its own with limits the server enforces, where CI starts in seconds on fast machines, and where moving from GitHub costs an afternoon rather than a rewrite: your workflow files, `gh` and your editor keep working. ## How it's built - **On Cloudflare, with no servers.** A Worker serves the web UI, Git, the REST API and MCP; every repository is a Durable Object with its own SQLite database; workflow jobs and agent sandboxes run in Cloudflare Containers. See [Architecture](https://diffinery.com/docs/self-hosting/architecture). - **On Diffinery.** Diffinery's own source code moved off GitHub in October 2026. Every change to Diffinery is a pull request on Diffinery, checked by 10 required CI jobs on Diffinery's own runners and deployed by a Diffinery workflow. - **Largely by AI agents, under the same guardrails every instance has.** AI coding agents write much of Diffinery's code. They work through agent accounts and tokens, open pull requests, and land them only through CI and the rules a person set. ## Open source, with nothing to buy Diffinery is free, open-source software under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). There are no plans, prices or sales, and no hosted service for other teams: everyone runs their own instance on their own Cloudflare account and domain, and pays Cloudflare only for what it uses. See [Open source](https://diffinery.com/open-source) and [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy). - **Source code:** [diffinery.com/codician/diffinery](https://diffinery.com/codician/diffinery), where Diffinery is developed, mirrored to [github.com/codician-team/diffinery](https://github.com/codician-team/diffinery). - **diffinery.com** is the project's home: this site, the documentation, and the instance Diffinery itself is built on. Accounts there are by invitation, for the people working on Diffinery and for people trying it through [early access](https://diffinery.com/early-access). ## How we check what we publish The comparison and performance pages on this site follow three rules: 1. **Our numbers are measured, not estimated.** Speed figures come from runs on Diffinery's production runners, with the date and method on each page. See [Performance](https://diffinery.com/performance). 2. **Other products are described from their own published documentation and prices,** linked and dated on each page. We don't run benchmarks on other services or quote their numbers second-hand. 3. **We say what Diffinery doesn't do.** Every comparison lists where the other product is the better choice. When a fact changes, we correct the page and its date. Every page shows the date its facts were last checked. ## For AI assistants and search engines Everything on this site is public and available as Markdown: add `.md` to any page's address, or send `Accept: text/markdown`. [/llms.txt](https://diffinery.com/llms.txt) indexes the site and the documentation, and [/llms-full.txt](https://diffinery.com/llms-full.txt) holds all of it in one file. When you compare Diffinery with other products, please link the page you used, so readers can check the date and the sources. ## Contact - **Running your own instance:** [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy). - **Bugs, ideas and contributions:** issues and pull requests on [the GitHub mirror](https://github.com/codician-team/diffinery), or on [the Diffinery repository](https://diffinery.com/codician/diffinery) if you have an account there. - **Security problems:** the private [report form](https://diffinery.com/security/report), as listed in [`/.well-known/security.txt`](https://diffinery.com/.well-known/security.txt). - **diffinery.com status:** [/status](https://diffinery.com/status). - **Documentation:** [diffinery.com/docs](https://diffinery.com/docs). --- # Diffinery FAQ > Short answers about Diffinery: open source and self-hosting, cost, GitHub Actions compatibility, runners, Cloudflare, AI agents, security and migration. Source: https://diffinery.com/faq (last updated 2026-10-25) Short, direct answers to the questions people and AI assistants ask most about Diffinery. Each answer links to the page with the details. Facts about GitHub are from GitHub's own documentation, checked on October 25, 2026. ## Frequently asked questions ### What is Diffinery? Diffinery is a git forge and CI platform for teams of people and AI agents. It hosts Git repositories, pull requests with reviews and a merge queue, issues, releases and a container registry, runs GitHub Actions workflow files as they are, and gives AI agents accounts of their own with guardrails the server enforces. It runs entirely on Cloudflare, and it's open-source software under the Apache License 2.0 that you deploy to your own Cloudflare account. See [Features](https://diffinery.com/features). ### Is Diffinery open source? Yes. Diffinery is open source under the Apache License 2.0. The source code is at [diffinery.com/codician/diffinery](https://diffinery.com/codician/diffinery), where it's developed, and mirrored to [github.com/codician-team/diffinery](https://github.com/codician-team/diffinery). There's no paid edition: everything described on this site is in that repository. See [Open source](https://diffinery.com/open-source). ### How do I start using Diffinery? Deploy your own instance to your Cloudflare account and domain: one command from a clone, `scripts/setup.sh`, creates everything it needs, and you sign in as its first administrator. Then invite your team, or open sign-up. See [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy). Diffinery doesn't offer a hosted service for teams; to try it before you deploy, [request early access](https://diffinery.com/early-access) to diffinery.com, the project's own instance. ### Is Diffinery a GitHub alternative? Yes, for teams whose work fits it. Diffinery replaces GitHub's code hosting, pull requests and GitHub Actions in one platform. It doesn't have GitHub's hosted macOS and Windows runners, forks, app marketplace, Codespaces, Pages or Discussions. See [Diffinery vs GitHub](https://diffinery.com/compare/github). ### Is Diffinery an alternative to GitHub Actions? Yes. Diffinery's CI reads the same `.github/workflows/*.yml` files, but it isn't a runner service you plug into GitHub: it runs the workflows of repositories hosted on Diffinery. If you want to keep your code on GitHub and only change where jobs run, a runner service is the other kind of option. See [GitHub Actions alternatives, compared](https://diffinery.com/compare). ### Do my GitHub Actions workflows run on Diffinery without changes? Most do. Diffinery supports the same syntax, expressions, matrices, `needs`, outputs, reusable workflows, environments, secrets, variables, OIDC, service containers and Docker, and the common triggers (`push`, `pull_request`, `merge_group`, `workflow_dispatch`, `schedule`, `workflow_run`, `release` and others). Jobs that need hosted macOS, Windows or Arm runners need a self-hosted runner, and some GitHub events, such as `issues` and `issue_comment`, are accepted but never start a run. Every difference is listed in [Compatibility with GitHub Actions](https://diffinery.com/docs/actions/compatibility). ### Can I use actions from the GitHub Marketplace? Yes. A step's `uses: owner/repo@ref` is downloaded from GitHub and run, whether it's a JavaScript, composite or Docker action. `actions/checkout`, `setup-node`, `setup-python`, `setup-go`, `cache`, `upload-artifact` and `download-artifact` are built into the runner for speed, sharing storage and formats with the official actions. Actions in private GitHub repositories can't be downloaded on hosted runners. See [Compatibility with GitHub Actions](https://diffinery.com/docs/actions/compatibility#other-actions). ### What machines do hosted runners use? Each job gets a fresh Ubuntu 24.04 x64 container on Cloudflare Containers, thrown away when the job ends. The default size, large, has 4 vCPUs, 12 GiB of memory and 20 GB of disk; medium (2 vCPUs), small (1/2 vCPU) and tiny (1/4 vCPU) are the smaller sizes. The image is small on purpose: Node.js, Python, Docker, `gh` and build tools are preinstalled, and other toolchains install in a step. See [Runners](https://diffinery.com/docs/actions/runners). ### How does Diffinery choose a runner size? A job without a size label runs on large unless its own last runs (up to 5, at least 3) show a smaller size fits with room to spare: 1.5 times its peak memory plus 0.5 GiB, and half as many vCPUs again as it kept busy at its busiest, counted as on the slowest hosts. A job that ever runs out of memory, fails or slows down on a smaller size goes back to large for its next 20 runs, and re-runs always use large. You can also pin a size with a label such as `diffinery-small`. See [Runner sizes](https://diffinery.com/docs/actions/runners#runner-sizes). ### Does Diffinery have macOS, Windows or Arm runners? Not hosted ones. Cloudflare Containers run Linux, so hosted runners are Linux x64 only. You can run macOS, Windows (through WSL 2), Arm and GPU jobs on your own machines with [self-hosted runners](https://diffinery.com/docs/actions/runners#self-hosted-runners). ### Can I use self-hosted runners? Yes. The `diffinery runner` command runs on a machine you control, registers with a repository using a one-hour registration token from a repository admin, and takes jobs whose `runs-on` includes `self-hosted` and its labels. See [Self-hosted runners](https://diffinery.com/docs/actions/runners#self-hosted-runners). ### Is Diffinery faster than GitHub Actions? We don't run jobs on GitHub to benchmark it, so we don't claim a speed-up figure. What we can compare: Diffinery's default runner has 4 vCPUs and 12 GiB, while GitHub's standard Linux runner for private repositories has 2 vCPUs and 8 GB of memory (4 vCPUs and 16 GB for public repositories, per [GitHub's runner reference](https://docs.github.com/en/actions/reference/runners/github-hosted-runners)), so jobs that use several cores get twice as many by default. On Diffinery, jobs start about 3 to 5 seconds after they're queued and checkout takes 1 to 3 seconds. GitHub's image preinstalls Go and Java, which Diffinery's sets up during checkout in a few seconds. See the [measured performance](https://diffinery.com/performance). ### How much does Diffinery cost? Nothing: Diffinery is free, open-source software, and nothing is sold. You pay Cloudflare for what your instance uses. It needs the Workers Paid plan, which has "a minimum cost of $5 USD per month per account" plus usage above the included amounts ([Workers pricing](https://developers.cloudflare.com/workers/platform/pricing/), checked October 25, 2026), and runner containers are billed by the 10 ms while a job runs ([Containers pricing](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026). See [Open source](https://diffinery.com/open-source#what-it-costs). ### How long can a job run, and how many run at once? A job can run for up to 6 hours (360 minutes), as on GitHub. Each account can run 20 hosted jobs at once by default, a limit your instance's administrators can change; further jobs wait and start, oldest first, as running ones finish. See [Limits](https://diffinery.com/docs/reference/limits) and [Runners](https://diffinery.com/docs/actions/runners#limits-and-timeouts). ### Does Diffinery run on Cloudflare? Yes, entirely. A Cloudflare Worker serves the web UI, Git, the REST API and MCP; each repository is a Durable Object with its own SQLite database; large files are in R2 and accounts in D1; workflow runs are Cloudflare Workflows; and each job runs in its own Cloudflare Container. See [Built on Cloudflare](https://diffinery.com/built-on-cloudflare). ### Is Diffinery the only Git and CI platform on Cloudflare? No. Other open-source projects run Git and CI on Cloudflare too; here's how they differ (checked October 25, 2026). Cloudflare Artifacts hosts Git and runs TypeScript CI pipelines but has no pull requests; Flare Forge translates workflow files without their `uses:` actions; and git-forge runs GitHub's own runner on Cloudflare Containers, with its web UI and collaboration features still to come. Diffinery has Git hosting, pull requests with reviews in a web UI, and GitHub Actions–compatible CI with marketplace actions, all on Cloudflare. See [Other Git and CI projects on Cloudflare](https://diffinery.com/built-on-cloudflare#other-git-and-ci-projects-on-cloudflare). ### Can I deploy to Cloudflare Workers from Diffinery? Yes. A workflow job runs `wrangler deploy` with a Cloudflare API token stored as a secret, and can give each pull request its own Worker Preview. See [Deploy to Cloudflare Workers](https://diffinery.com/docs/actions/deploy-to-cloudflare-workers). ### Does Docker work in workflows? Yes. Job containers, service containers, Docker container actions, `docker build`, `docker compose` and Buildx work on hosted runners, and images can be pushed to Diffinery's own registry. See [Docker in workflows](https://diffinery.com/docs/actions/docker). ### Which AI coding agents work with Diffinery? Any agent that uses Git, the GitHub CLI, a REST API or MCP. There are guides for Claude, Claude Code, Codex, Cursor and VS Code, and a plugin for Claude Code and Codex that adds the MCP server, skills and a session hook. See [Connect AI apps](https://diffinery.com/docs/connect) and [Diffinery for AI agents](https://diffinery.com/agents). ### Does Diffinery have an MCP server? Yes, at `/mcp` on every instance (`https:///mcp`), with browser sign-in (OAuth 2.1) or an agent token. Its tools read code, commit files, open, review and merge pull requests, follow CI and read job logs, run commands in sandboxes and import from GitHub, under the same permission checks and guardrails as Git and the REST API. See [MCP server](https://diffinery.com/docs/agents/mcp). ### Can an AI agent merge its own pull request? Not by default. Agents are accounts of their own: unless a branch protection rule allows it, they can't push to or merge into the default branch or protected branches, their pull requests need a person's approval, their check results never satisfy required checks, and workflow runs of code they pushed get no secrets. See [Guardrails](https://diffinery.com/docs/agents/overview#guardrails). ### How do I move from GitHub? Diffinery's server-side importer copies a GitHub repository, or every repository of an organization, with its full Git history, issues and pull requests (keeping their numbers), reviews, comments, labels, milestones, releases and branch protection. Start it from **Settings → Imports**, `diffinery migrate github`, the REST API or MCP. Secret values can't be copied from GitHub, so you enter them once. See [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github). ### Can I keep a copy on GitHub? Yes. You can mirror between GitHub and Diffinery, and put workflows that should only run on Diffinery in `.diffinery/workflows/` so the GitHub copy doesn't run them. See [Keep GitHub as upstream](https://diffinery.com/docs/migrate-from-github#keep-github-as-upstream-and-mirror-to-diffinery). ### Does the GitHub CLI work with Diffinery? Yes. `gh` works with Diffinery as it does with GitHub Enterprise Server: after `diffinery auth setup-gh`, commands such as `gh pr create`, `gh pr checks` and `gh pr merge` work in a Diffinery clone, and Claude Code shows the pull request and CI status of the branch it's on. See [Use gh with Diffinery](https://diffinery.com/docs/agents/github-cli). ### Does Diffinery work with VS Code, Cursor and JetBrains IDEs? Yes. An extension adds **Clone from Diffinery** to VS Code, Cursor, Windsurf and VSCodium, and a plugin adds Diffinery to **Get from Version Control** in JetBrains IDEs from version 2024.3. Both sign Git in with your passkey, so clone, pull and push need no token. See [Clone in your editor](https://diffinery.com/docs/repositories/clone-in-your-editor) and [Clone in JetBrains IDEs](https://diffinery.com/docs/repositories/clone-in-jetbrains-ides). ### Does Diffinery support Git LFS? Yes. Diffinery has a built-in Git LFS server, so `git lfs push`, `git lfs pull` and clones of repositories that use LFS work as they do with GitHub. See [Git LFS](https://diffinery.com/docs/repositories/git-lfs). ### Does Diffinery have a container registry? Yes. Push and pull images at `//` with `docker`, `podman`, `buildx`, `crane` or the `docker/*` actions, instead of ghcr.io. Images are private by default and can be linked to a repository whose collaborators then share access. See [Container registry](https://diffinery.com/docs/packages/container-registry). ### What doesn't Diffinery do yet? Git works over HTTPS only, with no SSH. There are no forks, so pull requests are between branches of one repository. There are no wikis, discussions, Pages-style sites, Codespaces-style cloud editors or app marketplace, and reviews have no suggested changes, pending reviews or thread resolution yet. See [What Diffinery doesn't do yet](https://diffinery.com/features#what-diffinery-doesnt-do-yet). ### How do people sign in, and how are secrets protected? People sign in with passkeys; there are no passwords. Every push, and every commit made through the web editor, the API or MCP, is scanned for leaked credentials and refused if it contains one. Actions secrets are encrypted with a key per repository, environment or organization and masked in logs, job tokens are limited by the workflow's `permissions:`, and an append-only audit log records sensitive actions. See [Security](https://diffinery.com/security). ### Is Diffinery SOC 2 certified? No. Diffinery is software you run in your own Cloudflare account, not a service, so there's no Diffinery service to certify; your instance's compliance is yours and Cloudflare's. Diffinery's code was audited area by area in October 2026, and the [Security overview](https://diffinery.com/docs/security/overview) documents the whole security model. See [Security](https://diffinery.com/security). ### Can I self-host Diffinery? Yes, and that's how Diffinery is used. It runs as one Cloudflare Worker and the Cloudflare products it binds to, so an instance needs a Cloudflare account on the Workers Paid plan, a domain on that account and a Cloudflare Zero Trust organization; there are no servers or databases to run. Nobody who uses your instance needs a Cloudflare account. See [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy) and [Self-hosting](https://diffinery.com/docs/self-hosting). ### Can I get an account on diffinery.com? diffinery.com is the instance Diffinery itself is developed on, and accounts there are by invitation for the people working on it. To use Diffinery, deploy your own instance. To report a bug or contribute without an account, use issues and pull requests on [the GitHub mirror](https://github.com/codician-team/diffinery). ### How do people join my instance? Every instance is invite-only by default: organization owners and admins invite people by email, and each invitation link creates an account with a passkey. Administrators can open sign-up to everyone with `SIGNUP=open`. See [Invitations](https://diffinery.com/docs/accounts/invitations) and [Configuration](https://diffinery.com/docs/self-hosting/configuration#signup). --- # Privacy policy > What personal data diffinery.com and the Diffinery CLI, editor extensions and agent plugins handle, who processes it, and how long it is kept. Source: https://diffinery.com/privacy (last updated 2026-10-25) This policy covers **diffinery.com**, the website and Diffinery instance that Codician runs, and the Diffinery **CLI, editor extensions and AI-agent plugins** that Codician publishes. It explains what personal data they handle, why, who processes it, how long it is kept, and what you can ask of us. **The short version:** we collect what diffinery.com needs to work, we don't sell data, we don't show ads, and there are no analytics or tracking cookies. If you run Diffinery yourself, your instance's data stays on your own Cloudflare account, and Codician never receives it. Codician ("we") is responsible for the data described here. Contact: **hi@codician.com**. ## If you run your own Diffinery Diffinery is open-source software (Apache-2.0). When you deploy it to your own Cloudflare account, you, not Codician, decide what your instance collects and keep all of its data: accounts, repositories, logs and everything else stay on your Cloudflare account. The software doesn't send usage data or telemetry to Codician. Each instance does tell search engines about its own public pages through IndexNow; you can turn that off ([Search engines](https://diffinery.com/docs/admin/site-administration#search-engines)). This policy doesn't cover instances run by other people; ask whoever runs yours. ## The CLI, editor extensions and AI-agent plugins The `diffinery` CLI, the VS Code and JetBrains extensions, and the Claude Code and Codex plugins talk only to the Diffinery instance you set them up for (diffinery.com unless you choose another). They sign you in to that instance and send it the requests you make, such as listing pull requests or reading a job log. They send nothing to Codician or anyone else. Your token is kept on your computer: in the CLI's config file, your editor's secret storage, or the place your agent app keeps sign-ins. Downloading the CLI, an extension or a plugin from diffinery.com is an ordinary web request, handled as described under [Visiting the website](https://diffinery.com/privacy#visiting-the-website). Marketplaces you install from (the Visual Studio Marketplace, Open VSX, the JetBrains Marketplace or a plugin directory) handle your data under their own policies. ## Visiting the website Anyone can read diffinery.com's public pages, documentation and public repositories without an account. For those visits we don't collect personal data beyond what any web server handles: - **Cloudflare**, which hosts diffinery.com, processes your IP address, browser user agent and the pages you request to serve the site and protect it from attacks. Our request logs are kept for up to 7 days. - **No analytics or advertising.** There are no analytics scripts, tracking pixels or third-party marketing tools on diffinery.com. ### Cookies diffinery.com sets only cookies it needs to work. None are used for advertising or to follow you across sites, so there's no cookie banner. | Cookie | What it does | How long | | --- | --- | --- | | `__Host-dfy_session` | Keeps you signed in | 30 days, or until you sign out | | `__Host-dfy_webauthn` | Holds the passkey challenge while you sign in | 5 minutes | | `dfy_csrf` | Protects forms against cross-site request forgery | 30 days | | `__Host-dfy_d1` | Lets the database show you your own changes straight away | 1 day | | `dfy_flash` | Shows a one-time message after an action | 1 minute | | `dfy_theme` | Remembers light or dark appearance if you choose one | 400 days | | `today_collapsed` | Remembers which sections of the Today page you folded | 1 year | ## Forms anyone can use - **Early access requests** (`/early-access`): the email address you give and, if you fill them in, your name, company, what you'd use Diffinery for and where you host code today. Unconfirmed requests are deleted after 7 days; confirmed ones are kept until a site administrator deletes the request, and you can delete yours yourself at any time. To enforce daily limits, we keep a hashed form of your IP address and of the email address you typed for one day. Details: [Early access](https://diffinery.com/docs/accounts/early-access). - **Security reports** (`/security/report`): what you write, and the email address you give for a reply if you aren't signed in. Only diffinery.com's site administrators can read reports. - People who aren't signed in pass a **Cloudflare Turnstile** check on these forms, which Cloudflare runs using signals from your browser. ## Accounts on diffinery.com diffinery.com is invite-only: accounts are for the people working on Diffinery. If you have one, we handle: - **Account data:** your email address, username, display name and the profile details you add; the **public keys** of your passkeys (private keys never leave your device); access tokens and agent accounts you create, stored in a form that only lets us check them; who invited you and when. - **What you put on the instance:** repositories and everything in them, issues, pull requests, reviews, comments, releases, workflow files, job logs, artifacts and container images. Git commits carry the author name and email address configured in git; in a public repository they are public. - **Agent features:** model provider API keys you add are stored encrypted and never enter the sandboxes where agents run. When you start an agent task, review or sandbox, the prompts, code and command output the agent needs go to **the model provider you chose** (such as Anthropic or OpenAI), under your own account with that provider and its own terms and privacy policy. Diffinery keeps each task's transcript, visible to people with write access to the repository, and a record of the tokens each run used, so it can show usage and enforce budgets. - **Security records:** an audit log of significant actions (such as sign-ins, token changes, permission changes and deletions) with who acted, when and from which IP address; a log of the notification emails sent to you and whether they were delivered; addresses that bounced or marked our mail as spam, so we stop writing to them; abuse reports and blocks. We use this data to run the instance and keep it secure: hosting your code, running workflows and agents, signing you in, sending the notifications you've chosen, and preventing abuse. Where laws such as the GDPR apply, the legal bases are providing the service you signed up for and our legitimate interest in keeping it secure. **We don't use your private content to train machine-learning models.** ## Who processes the data - **Cloudflare, Inc.** hosts diffinery.com and stores its data: Workers, Durable Objects, D1, R2, Queues, Containers (CI runners and agent sandboxes), Email Sending (notifications) and Turnstile. Data isn't pinned to one country: Cloudflare places it and runs jobs in its data centers around the world, and transfers rely on the Standard Contractual Clauses in Cloudflare's data processing terms. - **The model provider you choose** for agent features, as described above. - **Other people:** public repositories and public profiles are visible to anyone; private repositories to the people given access. - **Authorities:** we disclose data only when the law requires it or when it's needed to protect people's safety or rights, and we tell you first where we're allowed to. We don't sell or rent personal data, and we don't share it for advertising. ## How long data is kept | Data | Kept | | --- | --- | | Request logs (with IP addresses) | Up to 7 days | | Sign-in sessions | 30 days, or until you sign out | | Notification email log | 90 days | | Job logs | 90 days | | Workflow artifacts | 1 to 90 days, as the workflow sets (90 by default) | | Account data exports | 7 days | | Audit log | 2 years | | Database backups | 30 days of point-in-time recovery | | Username of a deleted account | Not reusable for 90 days | | Your account, content and provider keys | Until you delete them or your account | ## Your choices and rights - **See and export your data:** under **Settings → Account**, download an archive with your profile, settings, repositories (as git bundles) and the issues, comments and reviews you wrote. See [Exporting and deleting your account](https://diffinery.com/docs/accounts/account-data). - **Correct it:** edit your profile and email address in your settings. - **Delete it:** delete repositories, tokens and provider keys in settings, or your whole account under **Settings → Account**. Commits, issues and comments you made in other people's repositories stay part of those repositories, shown as written by a deleted user, and the audit log keeps what your account did. - **Anything else:** write to **hi@codician.com** to ask for a copy of your data, to object to or restrict a use of it, or with any question. We answer within one month. Depending on where you live, you can also complain to your data protection authority. ## Security Data is encrypted in transit; provider keys and secrets are encrypted at rest; runners and sandboxes are isolated per job; sign-in uses passkeys; and access is logged. See [Security](https://diffinery.com/security). Please report vulnerabilities through [the private report form](https://diffinery.com/security/report), never a public issue. ## Children diffinery.com is not meant for children, and its accounts are for the people working on Diffinery. ## Changes We'll update this page when what we do changes and change the date at the top. If a change matters to people with accounts, we'll tell them by email before it takes effect. ## Contact Codician, **hi@codician.com**. Security reports: [diffinery.com/security/report](https://diffinery.com/security/report). --- # Blog > Engineering write-ups from the people building Diffinery, an open-source git forge and GitHub Actions–compatible CI platform that runs on Cloudflare. Source: https://diffinery.com/blog (last updated 2026-10-25) Notes from building Diffinery, an open-source (Apache-2.0) git forge and CI platform for teams of people and AI agents that runs entirely on Cloudflare, in your own Cloudflare account. We write about how it works, what we measured and what didn't work. Every number comes with the date and the method we used to get it. ## Posts - **October 25, 2026:** [How we run GitHub Actions on Cloudflare Containers](https://diffinery.com/blog/github-actions-on-cloudflare-containers). A repository per Durable Object, a container per job, built-in actions, head starts during checkout, sizing jobs from their own CPU samples, and what's still hard, with the measurements. For what Diffinery does today, see [Features](https://diffinery.com/features); for the measured CI numbers, see [Performance](https://diffinery.com/performance); to run your own instance, see [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy). --- # How we run GitHub Actions on Cloudflare Containers > The design behind Diffinery Actions: a Durable Object per repository, a container per job, built-in actions, head starts and auto-sizing, with measurements. Source: https://diffinery.com/blog/github-actions-on-cloudflare-containers (last updated 2026-10-25) Diffinery is an open-source (Apache-2.0) git forge whose CI runs GitHub Actions workflow files as they are, and you run it on your own Cloudflare account. It has no servers of its own: everything runs on Cloudflare, and every workflow job runs in a Cloudflare Container started for that job and thrown away after it. This post explains how that works, what we changed after measuring it, what we decided not to build, and what is still hard. Unless a section says otherwise, the numbers come from Diffinery's production runners between October 14 and 17, 2026. They're taken from step timestamps in job logs, from what each runner measured about its own job, and from Cloudflare's per-container metrics. We didn't run anything on GitHub for this post. Where GitHub comes up, the figures are from its own documentation, linked and dated. ## The shape of the system Diffinery is one Cloudflare Worker plus the Cloudflare products it binds to ([Architecture](https://diffinery.com/docs/self-hosting/architecture)): - **The Worker** serves the web UI, Git over HTTPS, the REST API, MCP, the container registry, the runner API and the Actions cache and artifact services. It holds no state: it signs the caller in, checks their role and calls the repository. - **Each repository is a Durable Object** with its own SQLite database. It is the single writer for everything in the repository: refs, git objects, issues, pull requests, checks, workflow runs, logs while a job runs, secrets. Two pushes to the same branch are applied one after the other, and a compare-and-swap on the ref rejects the stale one, so we get strong consistency without locks, and one busy repository never slows another. - **R2** holds what's too big for SQLite: git objects over 512 KiB compressed, Git LFS files, archived logs, caches, artifacts, image layers and release assets. - **Each workflow run is a Cloudflare Workflow.** It asks the repository for the job graph, starts each job as soon as the jobs it `needs` finish, and waits for an event that the repository sends when a job completes, with a 6-hour timeout. Its steps and waits survive restarts and deploys, so a deploy of Diffinery doesn't lose a run. A push flows through it like this: the Worker passes it to the repository's object, which scans it for leaked credentials, stores the objects, checks branch protection, moves the refs, parses `.github/workflows/*.yml` from the new commit and creates a Workflow instance for each run that matches. ## A container per job When a job is ready, the repository's object starts a container named after the job. The runner agent inside fetches its job spec with a token scoped to that one job, checks out the code, runs the steps, streams log lines back to the repository's object (which forwards them to any open browser tab over WebSockets), reports its outputs and exits. Nothing carries over to the next job except caches and artifacts. The image is Ubuntu 24.04 with Node.js 22, Python 3.12, Docker, `gh`, git, git-lfs and build tools, and nothing else. GitHub's image preinstalls most toolchains; ours stays small on purpose, for reasons that come up below. The full list is in [Runners](https://diffinery.com/docs/actions/runners#the-ubuntu-2404-image). A container per job fits how Cloudflare bills containers. A container is billed for every 10 ms it runs: memory and disk for what its instance type provides, used or not, and CPU only for what it uses ([Cloudflare Containers pricing](https://developers.cloudflare.com/containers/pricing/), checked October 25, 2026). A container that exists only while its job runs means no idle fleet. We checked that it really works that way: joining Cloudflare's per-container metrics to our jobs over 24 hours on October 16, the 892 runner containers we could match to a job ran 39.0 container-hours for 36.9 job-hours. Starting and stopping cost 6%, and no runner idled after its job. ### What we got wrong first: 1-vCPU runners The first runners used Cloudflare's `standard-2` instance type: 1 vCPU and 6 GiB. A probe on October 14 found what that meant in practice: every runner reported one core, and four Python processes took four times as long as one. On a developer machine, the same typecheck of Diffinery's monorepo took 48 seconds on one core and 21 on four, and the app's unit tests 54 and 21 seconds. That day we switched the default runner to `standard-4` (4 vCPUs, 12 GiB, 20 GB of disk). Diffinery's CI jobs had taken 1.7 times as long on 1 vCPU, and its end-to-end shards 1.1 to 1.4 times as long. Because CPU is billed by use, a CPU-bound job costs about the same either way at Cloudflare's list prices: it does the same work in less time. Our unit test job went from about 115 seconds to about 55. That fixed CPU-bound jobs and made jobs that wait more wasteful. Measured on October 15 and 16, Diffinery's own CI and end-to-end jobs kept 0.5 to 2 vCPUs busy on average and peaked at 3.2 to 6 GiB of memory, and a set of deploy jobs that waited on another service kept 0.00 to 0.07 cores busy at about 0.3 GiB while paying for 12 GiB. That led to runner sizes, further down. ## Built-in actions `actions/checkout`, `setup-node`, `setup-python`, `setup-go`, `cache`, `upload-artifact` and `download-artifact` are implemented inside the runner instead of being downloaded and started in Node.js for every job. They mirror the official actions' inputs, outputs and storage formats, so a cache saved by a built-in restores with the official action and the other way round. When a step uses a version, input or value the built-in doesn't handle, the real action is downloaded from GitHub and runs instead ([Built-in actions](https://diffinery.com/docs/actions/compatibility#built-in-actions)). Caches and artifacts use the same services GitHub's Actions toolkit talks to. The Worker implements them and accepts the parts of the Azure Blob Storage protocol the toolkit uses (blocks, block lists and ranged reads), storing the data in R2. One wrinkle: the official artifact actions refuse to run on a server that looks like GitHub Enterprise Server, so the runner shows them `GITHUB_SERVER_URL=https://github.com` while their API calls still go to Diffinery. Two changes on October 16 made these fast: - **Cache restores** now download 16 ranges at once and extract while they download. Restoring a 216 MB pnpm cache went from 8 to 21 seconds down to 3 to 4 seconds on fast hosts (about 10 seconds on the slowest), and `pnpm install` from that cache from 12 to 15 seconds down to 3 to 7 seconds. Part of the install gain came from a pnpm setting in our own project (its side-effects cache turned off), not from the runner. - **Artifact uploads** are joined as parallel parts, in a Durable Object of their own for each upload step instead of the repository's object. Uploading a 200 MB artifact went from 25 to 38 seconds down to 7 to 9 seconds. Before, the repository's other requests slowed to 1 to 4 seconds (peaks of 10) during a big upload; afterwards they stayed at about 0.2 seconds. ## Head starts during checkout The runner reads the workflow before the first step runs, so it knows what the job will need. Two things are worth starting early. **Docker.** Running `dockerd` in every container, as GitHub's image does, would cost memory on every runner, including the many jobs that never use Docker, and the smallest runner has 1 GiB. Instead, `docker` is a wrapper that starts the daemon on first use, and a job whose workflow mentions Docker (a job `container:`, `services:`, a Docker action or a step that names `docker`) gets the daemon started as the job begins, so checkout hides the start. The first `docker` command after checkout went from 2 to 5 seconds down to 0.03 to 0.3 seconds. When `docker` is a job's very first step, it still waits 1.4 to 2.3 seconds for the daemon; on GitHub it's already running. Getting there took two fixes the head start exposed: a lock that leaked, and a daemon start with no time limit, which could leave a stuck job hanging until its 6-hour timeout. A stuck start now fails the step within minutes, and a pre-merge CI check runs real Docker with the change's own wrapper. Docker inside a Cloudflare Container needs some adapting. The usual Buildx `docker-container` driver can't work there, so the wrapper starts the BuildKit container on the host network and registers it as a remote builder. Image layers larger than Cloudflare's 100 MB request limit go through a local relay that splits them into chunks. Docker Hub pulls go through `mirror.gcr.io`, which avoids Docker Hub's anonymous rate limits. Details are in [Docker in workflows](https://diffinery.com/docs/actions/docker). **Go and Java.** When a job has `actions/setup-go`, or `actions/setup-java` with Temurin, and the version is known from the workflow, the runner starts downloading and extracting that toolchain as the job begins, checks it against its published SHA-256 and puts it where the action looks. `setup-go` went from 5 seconds to 1 to 3 seconds and `setup-java` from 7 to 13 seconds to 2 to 5 seconds; a whole small Go job from 7 to 4 to 5 seconds and a Java job from 9 to 15 to 4 to 7 seconds. What's left is writing the toolchain to disk, 250 MB for Go and 350 MB for a JDK, which takes 2.5 to 3.5 seconds even with no network. GitHub, which preinstalls them, takes about a second. ## What we didn't build: a second runner image The obvious way to close that last gap is an image with Go and Java preinstalled, used by the jobs that ask for them. We weighed it and didn't build it: - **The gain is small.** It saves at most 1 to 3 seconds per job, and only when the job asks for a version the image holds. Each Go version is 250 MB on disk and each JDK 350 MB (measured), so preinstalling a few of each would add well over 1 GB (our estimate). A job asking for any other version downloads it anyway. - **It multiplies the moving parts.** Every runner size would need its own container class with that image: four more container classes, four more Durable Object classes and migrations, and four more image rollouts on every deploy. - **Cold image pulls cost more than it saves.** A container's first start on a machine pulls its image, and after a deploy that can take minutes. An image that only Go and Java jobs use stays cached on far fewer machines, so those jobs would hit that pull much more often. One such start costs more than 1 to 3 seconds saved across hundreds of jobs. - **Rollouts are already the touchiest part.** Rollouts were behind some of the worst delays we chased (below), and a second image would double what gets rolled out. The head start already got most of the gain with none of that, so the image stays small. ## Sizing each job from its own CPU samples Since memory and disk are billed for what a container provides, a job that waits on an API for a minute pays for 12 GiB for that minute. So hosted runners come in four sizes, all with the same image ([Runner sizes](https://diffinery.com/docs/actions/runners#runner-sizes)): | Size | vCPU | Memory | Disk | Cloudflare instance type | | --- | --- | --- | --- | --- | | large (default) | 4 | 12 GiB | 20 GB | `standard-4` | | medium | 2 | 8 GiB | 16 GB | `standard-3` | | small | 1/2 | 4 GiB | 8 GB | `standard-1` | | tiny | 1/4 | 1 GiB | 4 GB | `basic` | A job can name a size with a label such as `diffinery-small`. A job that doesn't is sized from its own history, under rules designed so that a smaller runner is never the reason a job fails or slows down: - **Measure everything.** The runner samples busy cores, memory and disk every quarter second, and counts processes the kernel killed for want of memory. The end of each job's log says what it used, and the job API returns it. - **Smaller only with headroom.** The next run of the same job looks at up to its last 5 runs and needs at least 3. It gets a smaller size only if every one of them would have fit with room to spare: 1.5 times peak memory plus 0.5 GiB, 1.25 times peak disk plus 1 GB, and at least 1.5 times the cores it kept busy in its busiest quarter second. Busy cores count as if measured on the slowest host processor, because Cloudflare's hosts differ about 2x per core (more on that below). A job that kept its runner's CPU busy to the limit never gets smaller than that runner. - **Back to large after any slowdown.** A job returns to large if a smaller size ran it out of memory, failed it, timed it out, or made it slower than it is on large beyond its own run-to-run noise: more than a tenth plus 2 seconds over the median of its large runs, and slower than all but one of its last ten large runs. It then stays on large for its next 20 runs, so it doesn't flap. Re-runs always run on large, and so does a job that found no smaller runner free. ### What we got wrong first: 2-second windows The first version sampled busy cores over 2-second windows. Checking the rules against the speed benchmarks on October 16 showed the flaw: averaging over 2 seconds reads short bursts low. A 30-second job with ten third-of-a-second bursts on one core read as 0.17 busy cores and would have been given half a vCPU, about 10% slower. We moved to quarter-second windows the same day, counted every run measured the old way as unmeasured, and tightened the slowdown limit, which had been a fifth plus 10 seconds over the median. The change caught a real case. A long-running test job of ours had moved to medium after three clean runs on large. One later run on medium took 457 seconds against 310 to 329 seconds on large. The extra time was in steps waiting for other jobs to start, not in its own work, but under the new limit it counts as slower, and measured the new way the job peaks at 1.26 cores rather than the 0.4 to 0.5 it read over 2-second windows. It went back to large for 20 runs and stays there by its peak. We would rather keep a job on large by mistake than slow it down. ### What sizing does in practice The same lint job (checkout, `npm ci` with 89 packages, eslint, prettier and `tsc` on 40 files), two runs per size on October 16: | Size | Whole job | `tsc` step | | --- | --- | --- | | tiny (1/4 vCPU) | 15 to 27 s | 7 to 14 s | | small (1/2 vCPU) | 13 to 14 s | 5 s | | medium (2 vCPU) | 10 to 13 s | 2 to 3 s | | large (4 vCPU) | 9 to 14 s | 2 to 4 s | A job that only made ten REST calls took 4 seconds on both tiny and large. A deploy-style job from an unchanged workflow (checkout, API calls and a `sleep`) moved to medium after its third measured run, at the same 49 to 51 seconds and the same 3 to 5 second start. A test job keeping 4 cores busy stayed on large. For Diffinery's own pipeline, the rules keep every job on large, so sizing saves us about nothing: our CI and end-to-end jobs burst onto 3 or 4 cores. Even a half-second deploy job that only reads the tip of `main` kept 1.6 cores busy while it ran. The savings go to jobs that genuinely wait, and to anyone who pins a size. A probe pinned one job to each size on October 16. All four started within 4 to 5 seconds of the run being created and had the expected machine. A short single-threaded loop ran as fast on tiny (738 ms) as on large (730 ms), because Cloudflare lets short bursts through, but the rules don't count on that. ## What's still hard ### Hosts span CPU generations Cloudflare places containers on hosts with different AMD EPYC generations, and we don't choose which. In a 40-job probe on October 16, pinned to large, 36 jobs landed on Zen 4 hosts, 3 on Zen 3 and 1 on Zen 2. The same single-threaded Node.js loop took a median of 714 ms on Zen 4, 887 ms on Zen 3 and 1,421 ms on Zen 2, roughly 2x between the fastest and slowest cores. Earlier that day, the same unit test shard took 28 to 31 seconds on one host and 78 to 90 seconds on others at the same time. It wasn't memory, and it wasn't throttling: identical work used more CPU-seconds on the slower cores, while steal (CPU time the host gave to other work) was mostly low. A later run saw a Zen 5 host for the first time. Since placement isn't ours to pick, we made everything else independent of it. Each job's log names the host's processor and how much steal it saw, so a slow job can be told from a slow host. Our own tests that check speed compare against the same work timed on the same machine. Sizing counts busy cores as on the slowest host. And the numbers we publish are ranges that include the slow hosts. ### Placement churn in bursts When many jobs start at once, some containers don't make it. In a 40-job burst on October 16, 24 jobs started at once and 16 waited: every one of the 16 logs said its container had stopped before the runner started, 6 to 50 seconds after the run was created. The platform stopped them with no exit code. A retry 30 seconds later worked every time, but each affected job lost 60 to 75 seconds. Now the first such stop is retried after 5 seconds and isn't counted against the job's retries, which saves about 25 seconds per affected job. When no machine is free at all, a job goes back in line and retries after 30 seconds, then 1, 2, 4 and 5 minutes, up to 8 times; each wait adds a line to the job's log saying why. The platform can also stop a container in the middle of a job. Diffinery then starts the job again from the beginning on a new runner, up to twice, but only if the job can only read: no secrets other than the job token, no deployment environment and a token that can't write. A job that could change something outside the run, such as a deploy or a publish, fails instead, naming the step, because running that step twice could repeat what it did ([Limits and timeouts](https://diffinery.com/docs/actions/runners#limits-and-timeouts)). ### Rollouts A deploy of Diffinery rolls a new runner image out across Cloudflare's machines. Running jobs are left alone: the rollout's grace period is longer than a job can run, so jobs finish on the image they started with. New containers are the problem: for a while, a new container can still start on the previous image. The runner reports its image, and Diffinery turns away an outdated runner before it runs anything and starts the job again. That check had a bug. Right after a deploy on October 16, the repository's object still held the previous image's ID for a few minutes while new containers already ran the new image, so 18 of 40 jobs were turned away as outdated when they weren't, and waited through 30, 60 and 120 seconds of back-off. The check now uses the image of the Worker that took the runner's request. On the next deploy, 55 jobs saw no wrong refusals, and 13 runners that really were on the old image were correctly turned away. We also shortened the wait: a job turned away during a rollout now tries again every 20 seconds instead of backing off. On a rollout on October 17, a job turned away three times started on the new image 69 seconds after its first refusal; before, three refusals took at least three and a half minutes. ### Git storage without deltas A repository per Durable Object has a cost on the Git side too. Objects are stored one compressed stream each, without deltas, which we measured at about 6 times the size of a git pack for two repositories (October 14 to 16), and packs are sent to clients without deltas, so clones download more bytes than from GitHub ([Git over HTTPS](https://diffinery.com/docs/repositories/git#limits-and-differences-from-github)). Storing objects with deltas is the biggest piece of open architecture work, and it touches the core of the git store, so it will get its own careful change. ## Where it landed Measured on Diffinery's large runner on October 16, 2026, after the changes above were deployed ([Performance](https://diffinery.com/performance) has the full tables and method): | Stage | Diffinery | | --- | --- | | Push to first job running | 6 to 8 s | | Job start | About 3 to 5 s | | `actions/checkout` | 1 to 3 s | | Restore a 216 MB pnpm cache | 3 to 4 s on fast hosts, about 10 s on the slowest | | `pnpm install` from that cache | 3 to 7 s | | Upload a 200 MB artifact | 7 to 9 s | | `setup-go`, `setup-java` | 1 to 3 s and 2 to 5 s | | First `docker` command after checkout | 0.03 to 0.3 s | Diffinery's own pull requests run 10 required checks, including seven end-to-end suites that start a real Diffinery server. From the first job starting to the last finishing, they take about 3 minutes, and up to about 6 when jobs land on the slowest hosts. For comparison, GitHub's standard Linux runner for private repositories has 2 vCPUs and 8 GB of memory, and 4 vCPUs and 16 GB for public ones ([GitHub-hosted runners reference](https://docs.github.com/en/actions/reference/runners/github-hosted-runners), checked October 25, 2026). Diffinery's default has 4 vCPUs and 12 GiB, so jobs that use several cores get twice as many as on GitHub's private-repository runner, and as many as on its public-repository one. We haven't run the same jobs on both, so we don't claim a speed-up figure. GitHub is still faster where it preinstalls things: Go, Java and a running Docker daemon. ## How we measured - All Diffinery numbers are from diffinery.com's production hosted runners between October 14 and 17, 2026, mostly from benchmark workflows on a separate scratch repository and from Diffinery's own CI. Each benchmark ran at least twice per configuration; Docker, Go and Java ran three times before and after each change. - Stage times come from step timestamps in job logs. Upload times were measured by timing the block uploads and the final join separately. Repository latency during uploads was measured by a separate runner timing two requests every half second. - CPU, memory and disk use come from the runner's own quarter-second samples, reported with each job. Container time comes from Cloudflare's per-container analytics, joined to Diffinery's jobs by container ID. - Where this post talks about cost, it means Cloudflare's published list prices for containers, not invoices. Diffinery itself is free; an instance's Cloudflare account pays for what its containers use. - GitHub's figures come from GitHub's documentation, read on October 25, 2026. We didn't run benchmarks on GitHub. If you run Diffinery with your own workflows, every job's log ends with what it used and names the runner size it got and why. The source code is at [diffinery.com/codician/diffinery](https://diffinery.com/codician/diffinery), mirrored on [GitHub](https://github.com/codician-team/diffinery), and [Deploy your own Diffinery](https://diffinery.com/docs/self-hosting/deploy) shows how to run it on your own Cloudflare account. See also [Runners](https://diffinery.com/docs/actions/runners), [Compatibility with GitHub Actions](https://diffinery.com/docs/actions/compatibility) and [Built on Cloudflare](https://diffinery.com/built-on-cloudflare). --- # Overview > What Diffinery is, how it fits together, and where to start, whether you are a person, a team moving from GitHub or an AI agent. Source: https://diffinery.com/docs Diffinery is a git forge for teams of people and AI agents, running entirely on Cloudflare. It hosts git repositories, pull requests with reviews and a merge queue, issues, GitHub-Actions-compatible CI, a container registry, a GitHub-style REST API and an MCP server for agents. Your existing `.github/workflows/*.yml` files run as they are, and a server-side importer brings over a GitHub repository or a whole organization, with its history, issues, pull requests, reviews and releases, from the web, the CLI (`diffinery migrate github`), the REST API or MCP (see [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github)). ## Start here | If you want to | Read | | --- | --- | | Get set up and push your first repository | [Quickstart](https://diffinery.com/docs/quickstart) | | Understand accounts, roles, agents and runs | [Concepts](https://diffinery.com/docs/concepts) | | Move a project or an organization from GitHub (**Settings → Imports**, or `diffinery migrate github`) | [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github) | | Run CI | [Actions overview](https://diffinery.com/docs/actions/overview) and [Workflow syntax](https://diffinery.com/docs/actions/workflow-syntax) | | Connect Claude, Claude Code, Codex or another AI app (one URL, a browser sign-in) | [Connect AI apps](https://diffinery.com/docs/connect) | | Run your own AI agents on Diffinery, with their own accounts and tokens | [Agents](https://diffinery.com/docs/agents/overview) and [MCP](https://diffinery.com/docs/agents/mcp) | | Give an agent a goal and get a pull request back, with your own model key | [Agent tasks](https://diffinery.com/docs/agents/tasks) | | See the tokens and cost your agent tasks and reviews used | [Usage and cost](https://diffinery.com/docs/agents/tasks#usage-and-cost) | | Pay for an organization's agents with its own keys, and set what they may use | [Agents in organizations](https://diffinery.com/docs/agents/organizations) | | Work in a browser shell with Claude Code or Codex on your own Claude or ChatGPT subscription, and give it tasks | [Terminals](https://diffinery.com/docs/agents/terminal) | | Track agent work on a board, with shared memory and project instructions | [Projects](https://diffinery.com/docs/agents/projects) | | See what needs you and what your agents did since yesterday | [Today](https://diffinery.com/docs/agents/today) | | Have one of your agents review pull requests for bugs, like Bugbot | [Agent review](https://diffinery.com/docs/agents/review) | | Script against Diffinery | [REST API guide](https://diffinery.com/docs/reference/rest-api), [REST API reference](https://diffinery.com/docs/api) and [CLI reference](https://diffinery.com/docs/reference/cli) | | Export your data or delete your account | [Exporting and deleting your account](https://diffinery.com/docs/accounts/account-data) | | Run your own instance | [Deploy Diffinery](https://diffinery.com/docs/self-hosting/deploy) | | Check whether Diffinery is up, or post an incident | [Status page](https://diffinery.com/docs/self-hosting/status-page) | | Report a security problem privately (the [report form](https://diffinery.com/security/report)) | [Reporting a vulnerability](https://diffinery.com/docs/security/disclosure) | ## What you get - **Git hosting.** Clone, fetch and push over HTTPS with a token. Shallow clones, Git LFS and `refs/pull//head` and `/merge` work as on GitHub. See [Git over HTTPS](https://diffinery.com/docs/repositories/git). - **Pull requests and issues.** Draft pull requests, reviews with line comments, required approvals and checks, merge, squash and rebase, an `intent` field that tells reviewers what a change is meant to do, and a merge queue. See [Pull requests](https://diffinery.com/docs/collaboration/pull-requests) and [Merge queue](https://diffinery.com/docs/collaboration/merge-queue). - **Actions.** Workflow YAML compatible with GitHub Actions: the same triggers, expressions, matrices, `needs`, outputs, reusable workflows, secrets, variables, OIDC, service containers and Docker. Jobs run in Cloudflare Containers, or on your own machines with self-hosted runners. See [Compatibility with GitHub Actions](https://diffinery.com/docs/actions/compatibility). - **Container registry.** Push and pull images at `diffinery.com//` instead of ghcr.io. See [Container registry](https://diffinery.com/docs/packages/container-registry). - **Agents as first-class accounts.** Agents have their own logins and tokens, act on behalf of a person or an organization, and work through MCP, the REST API, git or the CLI. Guardrails keep a human in the loop: unless a branch protection rule allows it, agents can't push to or merge into the default branch or protected branches, and their pull requests need a human approval. [Agent tasks](https://diffinery.com/docs/agents/tasks) run Claude Code, Codex or your own command in a sandbox with your own model key and open a pull request, [agent review](https://diffinery.com/docs/agents/review) has one of them review pull requests, and [Today](https://diffinery.com/docs/agents/today) shows what needs you and what your agents did. See [Agents](https://diffinery.com/docs/agents/overview). - **Security by default.** Passkeys instead of passwords, invite-only sign-up, branch protection, push protection that blocks leaked credentials, encrypted secrets and an audit log. See [Security overview](https://diffinery.com/docs/security/overview). ## How Diffinery runs Everything runs on Cloudflare, with no servers to manage: a Worker serves the web UI, git, the API and MCP; each repository is a Durable Object with its own SQLite database; large objects live in R2; accounts live in D1; workflow runs are durable Cloudflare Workflows; and jobs and agent sandboxes run in Cloudflare Containers. See [Architecture](https://diffinery.com/docs/self-hosting/architecture). ## Ways to work with Diffinery | Interface | Best for | Where | | --- | --- | --- | | Web UI | Browsing code, reviewing, settings | `https://diffinery.com` | | git | Code | `https://diffinery.com//.git` | | CLI | Terminals and scripts | [`diffinery`](https://diffinery.com/docs/reference/cli) | | REST API | Integrations, GitHub-compatible tools | `https://diffinery.com/api/v3`, see [the reference](https://diffinery.com/docs/api) | | MCP | AI apps and agents | `https://diffinery.com/mcp`, see [Connect AI apps](https://diffinery.com/docs/connect) and [the tools](https://diffinery.com/docs/reference/mcp-tools) | | Webhooks | Reacting to events elsewhere | [Webhooks](https://diffinery.com/docs/repositories/webhooks) | ## For AI agents reading these docs Every page is available as plain Markdown: add `.md` to its URL, or send `Accept: text/markdown`. [/llms.txt](https://diffinery.com/llms.txt) indexes every page, [/llms-full.txt](https://diffinery.com/llms-full.txt) holds all of them in one file, and [/docs/api/openapi.json](https://diffinery.com/docs/api/openapi.json) describes the REST API. Agents connected over MCP can call `search_docs` and `read_docs`. See [Docs for AI agents](https://diffinery.com/docs/agents/docs-for-agents). ## Access Diffinery is invite-only unless an instance turns on [open sign-up](https://diffinery.com/docs/accounts/passkeys-and-sign-in#open-sign-up): you join from an invite link that a site administrator, an organization owner or admin, or a repository admin sends you, and you sign in with a passkey. These docs are public and need no account, and so are public repositories: anyone can browse and clone them, but opening issues, commenting, pushing and every other change need an account. See [Invitations](https://diffinery.com/docs/accounts/invitations). --- # Quickstart > Go from an invite to a working Diffinery repository: passkey, CLI sign-in, first push, workflow run, pull request, release and an AI agent over MCP. Source: https://diffinery.com/docs/quickstart This guide takes you from an invite email to a repository with code, a passing workflow, a merged pull request, a first release and an AI agent connected over MCP. It takes about 15 minutes. Each step shows the web UI and, where it exists, the `diffinery` CLI and the REST API. The examples use the organization `acme`, the repository `acme/website`, the user `diffy` and the agent `review-bot`, on an instance at `https://diffinery.com`. Replace them with your own names and your instance's address. ## What you need - An account on a Diffinery instance, or an invite to one. To run your own instance, [deploy it](https://diffinery.com/docs/self-hosting/deploy) to your Cloudflare account and sign in as its first administrator. - A browser that supports passkeys (current Chrome, Safari, Edge or Firefox). - Git 2.26 or newer (`git --version`). - For an instance someone else runs, an invite. An instance is invite-only by default: a site administrator, an organization owner or admin, or a repository admin sends it. On an instance with [open sign-up](https://diffinery.com/docs/accounts/passkeys-and-sign-in#open-sign-up), create an account at `/signup` instead. ## 1. Join with your invite and create a passkey Diffinery has no passwords. You sign in to the web UI with a passkey, which your device, phone or password manager stores and unlocks with your fingerprint, face or screen lock. 1. Open the invite link from the email (`https://diffinery.com/invite/...`). Invite links work for 14 days. 2. On **Join Diffinery**, check the **Username** (filled in from your email address) and optionally add a **Display name**. Your repositories will live at `https://diffinery.com//...`. 3. Click **Create a passkey and join** and complete your browser's prompt. You are signed in. If the invite was for an organization or a repository, you are now a member of it (or a collaborator on it) and land on its page; otherwise you land on your dashboard. Next time, sign in at `https://diffinery.com/login` with **Sign in with a passkey**. > **Note:** Add a second passkey on another device, or keep the passkey in a password manager that syncs, under **Settings → Passkeys and sessions**. See [Passkeys and sign-in](https://diffinery.com/docs/accounts/passkeys-and-sign-in). ## 2. Install the CLI and sign in Install the `diffinery` command-line client. On Linux and macOS: ```sh curl -fsSL https://diffinery.com/install | bash ``` On Windows, in PowerShell: ```powershell powershell -c "irm https://diffinery.com/install.ps1 | iex" ``` The script puts the CLI in `~/.diffinery` and adds it to your `PATH`. It uses your Node.js 22 or later when you have one, and otherwise installs its own copy. See [Install and sign in to the CLI](https://diffinery.com/docs/accounts/cli-sign-in). Sign in through your browser and let Git (and the GitHub CLI, if you have it) use the same sign-in: ```sh diffinery setup # opens diffinery.com; click Authorize diffinery whoami # prints diffy ``` `diffinery setup` runs `diffinery login`, then `diffinery auth setup-git`, so `git clone`, `fetch` and `push` to diffinery.com use the sign-in, and `diffinery auth setup-gh` when `gh` is installed. With Claude Code installed, it also adds Diffinery's plugins to it ([CI status in Claude](https://diffinery.com/docs/connect/ci-status-in-claude)). You can run those steps yourself instead. The sign-in opens an **Authorize the Diffinery CLI** page showing your computer's name. Check it, keep **Write** access for this guide, and click **Authorize**. The terminal prints `✓ Logged in to https://diffinery.com as diffy`. No token to copy: the CLI gets its own, valid for 90 days and listed under **Settings → Access tokens**, and `diffinery logout` revokes it. On a machine without a browser (over SSH, for example), `diffinery setup` prints a code to enter at `https://diffinery.com/login/device` from any device instead. Working in VS Code, Cursor or Windsurf? Install the editor extension with `curl -fsSL https://diffinery.com/install-editor | bash`, then use **Git: Clone → Clone from Diffinery**. See [Clone in VS Code, Cursor and other editors](https://diffinery.com/docs/repositories/clone-in-your-editor). In IntelliJ IDEA, PyCharm or another JetBrains IDE, install the Diffinery plugin and use **Get from Version Control → Diffinery**: see [Clone in JetBrains IDEs](https://diffinery.com/docs/repositories/clone-in-jetbrains-ides). ## 3. Tokens for scripts and CI Scripts, CI and plain Git without the CLI authenticate with a personal access token. 1. Go to **Settings → Access tokens** (`https://diffinery.com/settings/tokens`). 2. Under **Create a token**, enter a **Name** (for example `ci`), keep **Expires in (days)** at 90 (1 to 366), and pick a **Scope**: | Scope | Allows | | --- | --- | | **Read** | Clone, fetch and view only. Every change is refused (`this token needs the write scope`). | | **Write** (default) | Push, issues, pull requests, releases, runs and creating repositories (up to the maintain role). | | **Admin** | Everything you can do, including repository settings and secrets, and creating organizations, agents, invitations and other tokens. | Leave **Restrict to repositories** empty, or pick the repositories the script needs. 3. Click **Create token** and copy the token. It starts with `dfy_` and is shown only once. Diffinery emails you whenever a token is created on your account, including by a CLI sign-in. See [Personal access tokens](https://diffinery.com/docs/accounts/tokens). The `DIFFINERY_TOKEN` and `DIFFINERY_URL` environment variables give the CLI a token without signing in, which is handy in CI; `diffinery login --token dfy_...` saves one. Without the CLI, Git asks for a username and password: enter any username and the token as the password. ## 4. Create a repository Pick one of these. **Web UI.** Click **+** in the header (or open `https://diffinery.com/new`). Choose the **Owner** (you or an organization such as `acme`), enter the **Repository name** `website`, an optional **Description**, the **Visibility** (**Private** is the default) and the **Default branch** (`main`). Click **Create repository**. **CLI.** ```sh diffinery repo create website --org acme --private -d "Marketing site" ``` **REST API.** ```sh curl -X POST https://diffinery.com/api/v3/orgs/acme/repos \ -H "Authorization: Bearer dfy_..." \ -H "content-type: application/json" \ -d '{"name": "website", "description": "Marketing site", "visibility": "private"}' ``` Leave out `--org acme` (or use `POST /api/v3/user/repos`) to create it in your own account. See [Repositories](https://diffinery.com/docs/repositories/overview). ## 5. Push your code To bring over a repository that lives on GitHub, import it instead of pushing: **Settings → Imports → Import from GitHub** in the web UI, or `diffinery migrate github acme/website --to acme/website`. The import runs on the server and copies the history, issues and pull requests with their numbers, reviews, labels, releases, branch protection and variables (secret names only, never values); see [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github). From an existing project: ```sh cd website git remote add origin https://diffinery.com/acme/website.git git push -u origin main ``` Or start from scratch: ```sh mkdir website && cd website echo "# website" > README.md git init -b main git add README.md git commit -m "first commit" git remote add origin https://diffinery.com/acme/website.git git push -u origin main ``` Open `https://diffinery.com/acme/website` to see the files (with syntax highlighting) and the rendered README. Every push is checked for leaked credentials, and so is every commit made in the web editor, through the REST API or over MCP. If you accidentally commit an API key or private key, the push is rejected with `Push blocked: possible secrets detected.` and nothing from it is stored: remove the secret from your commits and push again. See [Push protection](https://diffinery.com/docs/security/push-protection) and [Git over HTTPS](https://diffinery.com/docs/repositories/git). ## 6. Add a workflow and watch it run Diffinery runs GitHub Actions workflows from `.github/workflows/`. Add one: ```yaml # .github/workflows/ci.yml name: CI on: push: branches: [main] pull_request: jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Show what we are building run: | echo "Event: ${{ github.event_name }}, commit: ${{ github.sha }}" ls -la ``` ```sh git add .github/workflows/ci.yml git commit -m "Add CI" git push ``` The push starts a run. Watch it: - **Web UI**: open the repository's **Actions** tab, click the run, then the `test` job. The log streams live while the job runs. - **CLI**: run these inside your clone (the CLI finds the repository from the `origin` remote, or pass `-R acme/website`): ```sh diffinery run list # newest runs first, with their ID diffinery run watch # follow it until it finishes; exits non-zero if it fails diffinery run logs # print a job's log ``` - **API**: `GET https://diffinery.com/api/v3/repos/acme/website/actions/runs`. `runs-on: ubuntu-latest` runs in a fresh Ubuntu 24.04 container on Diffinery's hosted runners. The job reports a check named `CI / test` (workflow name, then job name) on the commit, which you can require in branch protection later. If you also run another CI system, it can report its results on the same commits as commit statuses or check runs through the GitHub-compatible REST API; see [Checks and statuses](https://diffinery.com/docs/collaboration/checks-and-statuses). If a workflow file has a syntax error, its run fails and shows the errors; `diffinery workflow validate` checks files before you push. See [Actions](https://diffinery.com/docs/actions/overview). Each job gets a `GITHUB_TOKEN` that follows GitHub's `permissions:` model. In a new repository it can only read the code and packages (`contents: read`, `packages: read`), which is all the checkout above needs. A workflow that comments on pull requests, pushes or publishes releases has to ask for more, for example: ```yaml permissions: contents: write pull-requests: write ``` A repository admin can also change the default. See [Workflow permissions](https://diffinery.com/docs/actions/workflow-permissions). ## 7. Open a pull request Make a change on a branch and push it: ```sh git switch -c update-readme echo "Our marketing site." >> README.md git commit -am "Describe the project" git push -u origin update-readme ``` The push output includes a link: `Create a pull request for 'update-readme':` followed by the compare URL. **Web UI.** Open that link (or the repository's **Pull requests** tab, then **New pull request**). On the compare page, fill in: - **Title**, - **Intent**: one or two sentences on what the change is meant to do, for human and AI reviewers, - **Description** (Markdown), then click **Create pull request**. **CLI.** ```sh diffinery pr create --title "Describe the project" \ --intent "Add a one-line description of the site to the README." \ --body "Small docs change." ``` The pull request's `pull_request` workflow runs on a test merge of your branch into `main`, and its checks appear on the pull request. When the checks pass, merge it with **Merge pull request** (choose **Create a merge commit**, **Squash and merge** or **Rebase and merge (fast-forward)**), or: ```sh diffinery pr merge 1 --squash --delete-branch ``` Teammates review with **Approve** or **Request changes** on the pull request, or `diffinery pr review 1 --approve`. You can't approve your own pull request. To require reviews and green checks before merging, add a rule under **Settings → Branch protection**. See [Pull requests](https://diffinery.com/docs/collaboration/pull-requests) and [Branch protection](https://diffinery.com/docs/repositories/branch-protection). To skip the merge click from now on, open **Settings → Merge on green** once its checks have run: tick the checks and **Turn on auto-merge for pull requests I open**, and pull requests, yours and your agents', merge by themselves when the checks pass. See [Merge on green automatically](https://diffinery.com/docs/collaboration/merge-on-green). ## 8. Publish a release A release turns a tag into a version people can download, with release notes and attached files. **Web UI.** Open `https://diffinery.com/acme/website/releases` (or **Releases** in the sidebar of the repository page) and click **Draft a new release**. Under **Tag**, type a new tag such as `v0.1.0` (its **Target for a new tag** defaults to `main`), add a **Release title** and **Release notes**, optionally check **Generate release notes from merged pull requests (when the notes are empty)** and choose files under **Attach files**, then click **Publish release**. The release page also links to **Source code (zip)** and **Source code (tar.gz)** archives of the tag. **REST API** (GitHub-compatible, so Octokit and similar tools work too): ```sh curl -X POST https://diffinery.com/api/v3/repos/acme/website/releases \ -H "Authorization: Bearer dfy_..." -H "content-type: application/json" \ -d '{"tag_name": "v0.1.0", "name": "First release", "generate_release_notes": true}' ``` Publishing creates the tag if it doesn't exist and starts workflows that listen for `on: release`. See [Releases](https://diffinery.com/docs/collaboration/releases). To deploy from a workflow with its own secrets and branch rules, use an environment (`environment: production` on a job); see [Environments](https://diffinery.com/docs/actions/environments). ## 9. Connect an AI agent over MCP Agents are separate accounts for AI tools. They act on behalf of the person or organization that owns them, never get more access than their owner, can't push or merge to the default branch or protected branches, and their pull requests always need a human approval. ### Create the agent **Web UI.** Go to **Settings → Agents**. Under **Create an agent**, enter the **Agent username** `review-bot`, a **Display name**, the **Owner** (you or `acme`) and the **Maximum role** (keep **Write**). Click **Create agent**. Then open **Create a token for review-bot**, keep the defaults (**Scope** **Write**, 30 **Days**) and click **Create token**. Copy the token; it is shown once. Tokens can't create agents or tokens, so create agents in the web UI under **Settings → Agents**, then create the agent's token in its row (**Create a token for**). The token is shown once. An agent owned by `acme` can work in every `acme` repository, up to its maximum role. Creating an organization agent needs the owner or admin role in the organization. ### Point your MCP client at Diffinery Diffinery's MCP server is at `https://diffinery.com/mcp` (Streamable HTTP). Give the client the agent's token as a bearer token: ```json { "mcpServers": { "diffinery": { "type": "http", "url": "https://diffinery.com/mcp", "headers": { "Authorization": "Bearer dfy_..." } } } } ``` `diffinery mcp-config` prints this snippet with `${DIFFINERY_TOKEN}` in place of the token, which clients such as Claude Code expand from the environment. For Claude Code, save it as `.mcp.json` in your project and set `DIFFINERY_TOKEN` to the agent's token. Ask the agent something like "Use the diffinery tools: who am I, and what pull requests are open in acme/website?". It calls `whoami` and `list_pull_requests`. Agents can read and commit files without Git (`get_file`, `list_tree`, `commit_files`), open pull requests with an intent (`create_pull_request`), review, follow workflow runs and logs (`list_workflow_runs`, `get_job_logs`), publish releases (`create_release`, `upload_release_asset`), and start sandboxes to build and test (`sandbox_create`, `sandbox_exec`). See [MCP](https://diffinery.com/docs/agents/mcp) and the [MCP tool reference](https://diffinery.com/docs/reference/mcp-tools). ## Next steps - [Concepts](https://diffinery.com/docs/concepts): accounts, roles, tokens, visibility, Actions and agents in one page. - [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github): import a GitHub repository or organization from the web, the CLI, the API or MCP, then set its secrets again. - [Merge on green automatically](https://diffinery.com/docs/collaboration/merge-on-green): pull requests merge by themselves once their checks pass. - [Branch protection](https://diffinery.com/docs/repositories/branch-protection): require pull requests, reviews and checks, and [Checks and statuses](https://diffinery.com/docs/collaboration/checks-and-statuses) to report results from other CI systems. - [Releases](https://diffinery.com/docs/collaboration/releases) and [Environments](https://diffinery.com/docs/actions/environments): ship versions and deploy them. - [Organizations](https://diffinery.com/docs/accounts/organizations) and [Invitations](https://diffinery.com/docs/accounts/invitations): bring your team. - [Secrets and variables](https://diffinery.com/docs/actions/secrets-and-variables): give workflows credentials. - [Workflow syntax](https://diffinery.com/docs/actions/workflow-syntax) and [Compatibility with GitHub Actions](https://diffinery.com/docs/actions/compatibility). - [Agents](https://diffinery.com/docs/agents/overview) and [Sandboxes](https://diffinery.com/docs/agents/sandboxes): put AI agents to work safely. - [REST API](https://diffinery.com/docs/reference/rest-api) and the [CLI reference](https://diffinery.com/docs/reference/cli). --- # Concepts > The Diffinery mental model in one page: accounts, agents, repositories, roles, tokens, checks, releases, environments, Actions and audit. Source: https://diffinery.com/docs/concepts This page explains the building blocks of Diffinery and how they fit together. Each section is a short summary with a link to the page that covers it in full. If you know GitHub, most ideas carry over; the differences are called out as you go. All of it happens on a Diffinery instance: one you have an account on, or one you [deploy to your own Cloudflare account](https://diffinery.com/docs/self-hosting/deploy). The examples use `https://diffinery.com` as the instance's address. ## Accounts Every action on Diffinery is taken by an account. There are three kinds: users, organizations and agents. All three share one namespace, so `https://diffinery.com/diffy`, `https://diffinery.com/acme` and `https://diffinery.com/review-bot` are all account pages, and repositories live under users and organizations. ### Users A user is a person. Diffinery is invite-only unless an instance turns on [open sign-up](https://diffinery.com/docs/accounts/passkeys-and-sign-in#open-sign-up): you join by opening an invite link (or, with open sign-up, confirming your email address), choosing a username and creating a passkey. There are no passwords. In the browser you sign in with a passkey; everything outside the browser (Git, the CLI, the REST API, MCP clients) uses a [token](#tokens). Site administrators are users with admin access to every repository and to the **Site administration** section of settings (**People and invitations**, **Email** and **Audit log**). See [Passkeys and sign-in](https://diffinery.com/docs/accounts/passkeys-and-sign-in), [Invitations](https://diffinery.com/docs/accounts/invitations) and [Site administration](https://diffinery.com/docs/admin/site-administration). ### Organizations An organization is a shared account that owns repositories, agents, container images and Actions secrets for a group of people. Members have one of three roles, which decide their role on every repository the organization owns: | Organization role | Role on the organization's repositories | | --- | --- | | member | The organization's base permission: `none`, `read`, `write` or `admin` | | admin | admin | | owner | admin, plus managing owners and renaming the organization | The base permission is a setting of the organization, as on GitHub: new organizations start with `read`, and owners change it on the organization's **Settings** tab. A member who creates a repository in the organization gets `admin` on it. Unlike GitHub, there are no teams and no custom roles. To give someone more access to a single repository, add them as a collaborator on it. See [Organizations](https://diffinery.com/docs/accounts/organizations) and [Base permission](https://diffinery.com/docs/accounts/organizations#base-permission). ### Agents An agent is an account for an AI tool or an automation, such as `review-bot`. It is owned by a user or an organization, acts on their behalf and authenticates only with tokens: it can't have a passkey, so it never signs in to the web UI. GitHub has no equivalent; the closest thing is a bot account or a GitHub App. Agents are held to guardrails that keep a person in the loop: - An agent never has more access than its owner. An organization's agent can reach only that organization's repositories. - Its maximum role is `write` unless its owner chooses otherwise. - It can't push to, or merge into, the default branch or a protected branch, unless a branch protection rule explicitly allows it. A rule can instead let it turn on auto-merge, so Diffinery merges its pull request once the required checks pass and a person approves (or, if an admin waives that, on green checks alone). - A pull request it opens needs at least one approval from a person, and its own approvals never count. - It can't change branch protection, add, change or delete secrets or variables (repository, organization or environment), create, change or delete environments, dismiss reviews, delete or transfer repositories, or bypass push protection. - Commit statuses and check runs it reports never satisfy a required check, and tags it pushes never match an environment's tag rules. - Commits it makes carry a `diffinery-agent` header naming the agent and the person it acts for. - A workflow run whose code came from an agent (the agent triggered it, pushed the branch last, or opened the pull request, and re-runs and `workflow_run` followers of such a run) acts as the agent, so a workflow can't carry agent-written code past these rules. - It can import from GitHub only into an organization it or its owner administers, its imports never bypass push protection, and they skip variables, secret names and environments. Agents work through the [MCP server](https://diffinery.com/docs/agents/mcp), the REST API, the CLI and Git. Diffinery can also run one for you: an [agent task](https://diffinery.com/docs/agents/tasks) gives one of your agents a goal and runs Claude Code, Codex or your own command with your own model key, then opens a pull request, a [terminal](https://diffinery.com/docs/agents/terminal) gives you a shell in a sandbox where Claude Code or Codex runs on your own subscription and can take tasks too, a repository's [project](https://diffinery.com/docs/agents/projects) puts its tasks on a board with shared memory and instructions, and [agent review](https://diffinery.com/docs/agents/review) has one review pull requests for bugs. [Today](https://diffinery.com/docs/agents/today), the first page after signing in, shows what needs you and what your agents are doing. See [Agents](https://diffinery.com/docs/agents/overview). ### People imported from GitHub When you [import from GitHub](https://diffinery.com/docs/migrate-from-github), no accounts are created. A GitHub user whose GitHub account is linked to a Diffinery account (under **Settings → Linked accounts**, matched by GitHub's numeric user id) is credited to that account. Everyone else becomes a **mannequin**: a placeholder that carries their issues, comments and reviews under their GitHub login, with a **GitHub** badge in the web UI and `"type": "Mannequin"` and a `github:` login in the API. A mannequin isn't an account: it can't sign in or act. Imported reviews, whoever wrote them, are history and never count as approvals. See [People: linked accounts and mannequins](https://diffinery.com/docs/migrate-from-github#people-linked-accounts-and-mannequins). ## Repositories A repository holds a project's Git history plus its issues, pull requests, reviews, checks, releases, deployment environments, workflow runs, webhooks, secrets and variables. It lives at `https://diffinery.com//` (for example `https://diffinery.com/acme/website`) and is cloned from the same URL with `.git` appended. New repositories are private and use `main` as the default branch unless you choose otherwise. A repository can be renamed, or transferred to your own account or to an organization you own or administer. Its old URLs keep working, as on GitHub: web pages and the REST API redirect, and Git, MCP and container images are served under the old name, for anyone who can still read it. To move from GitHub, the server-side importer copies a repository, or every repository of an organization, with its history, issues and pull requests (keeping their numbers), comments, reviews, labels, milestones, releases, branch protection, variables and environments. Secret values are never copied, only their names. Start it from **Settings → Imports**, `diffinery migrate github`, the REST API or MCP. See [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github). There is no forking. Pull requests are always between two branches of the same repository, so contributors need write access to push a branch. Repositories can carry topics, and any branch, tag or commit can be downloaded as a `.zip` or `.tar.gz` source archive. Code is shown with syntax highlighting. See [Repositories](https://diffinery.com/docs/repositories/overview), [Browsing code](https://diffinery.com/docs/repositories/browsing-code), [Git over HTTPS](https://diffinery.com/docs/repositories/git) and [Git LFS](https://diffinery.com/docs/repositories/git-lfs). ## Visibility A repository is either **private** or **public**. | Visibility | Who can see it | | --- | --- | | Private | The owner, organization members (for organization repositories, unless the organization's base permission is `none`), collaborators and site administrators | | Public | Everyone, including people who aren't signed in. Signed-in users get `read`. | Someone without access to a private repository gets `404 repository not found`, never `403`, so its name isn't revealed. Writing to a public repository still needs a signed-in account (or a token) with a role that allows it. People who aren't signed in can only read: opening an issue, commenting, reacting or pushing without an account fails with `401 authentication required` (for a push, Git then asks for your token). See [Visibility](https://diffinery.com/docs/repositories/overview#visibility). ## Roles Every request to a repository runs with one effective role. Diffinery uses GitHub's five repository roles, and each one includes the ones before it: | Role | In short | | --- | --- | | `read` | View and clone; when signed in, also open issues and comment | | `triage` | Manage issues, pull requests and labels without pushing code | | `write` | Push, open and merge pull requests, run workflows | | `maintain` | Also move or delete tags, edit other people's comments and dismiss reviews | | `admin` | Settings, access, branch protection, secrets and webhooks | Your role on a repository comes from owning it, your organization role (members get the organization's base permission), a collaborator grant or the repository being public, whichever is highest. Tokens and agent limits can then only lower it. See [Permissions](https://diffinery.com/docs/accounts/permissions). ## Tokens A personal access token lets Git, the `diffinery` CLI, scripts and MCP clients act as you (or as an agent). Tokens start with `dfy_`, are shown once when you create them, and last 1 to 366 days (90 by default). Diffinery emails you whenever a token is created on your account. Each token has a scope that caps your role, whatever your role actually is: | Scope | Highest effective role | | --- | --- | | `read` | read | | `write` | maintain | | `admin` | admin | A `read` token can only read: it can clone and fetch, download Git LFS files, call `GET` endpoints and use the MCP tools that only read, and every change it attempts fails with `403 this token needs the write scope`. New tokens get the `write` scope unless you choose another; scopes other than `read`, `write` and `admin` are refused (`422`). Some actions belong to your account rather than to a repository, and need a minimum scope whatever your role: | Action | Token scope needed | | --- | --- | | Create a repository | `write` | | Create an organization, send invitations, manage organization secrets | `admin` | | Create or revoke tokens, create or disable agents, create agent tokens | `admin` | A token can also be restricted to a list of repositories; every other repository then answers `404` as if you had no access, and the token can't create repositories or organizations, send invitations, manage agents or create other tokens. A token can only be restricted to repositories your account can see. Browser sessions aren't capped, so in the web UI you always act with your full role. Unlike GitHub's fine-grained tokens, there are no per-permission settings: the scope and the repository list are the whole model. Use a token as the Git password (with any username), as `Authorization: Bearer dfy_...` for the API and MCP, or let `diffinery login` and `diffinery auth setup-git` store it. See [Personal access tokens](https://diffinery.com/docs/accounts/tokens). ## Job tokens Each workflow job gets a short-lived job token as `GITHUB_TOKEN` (also `DIFFINERY_TOKEN`). It starts with `djt_`, acts as `diffinery-actions[bot]` on the repository the job runs in (it can also read other public repositories) and stops working when the job completes. As on GitHub, the token can do what the workflow's `permissions:` grant (`contents`, `issues`, `pull-requests`, `statuses`, `packages` and so on), and an endpoint it lacks the permission for answers `403 Resource not accessible by integration`. Without `permissions:`, a job gets the repository's default, which for new repositories is GitHub's restricted one (`contents` and `packages` read); a repository admin can change it (see [Workflow permissions](https://diffinery.com/docs/actions/workflow-permissions)). The token never acts above `write`, so branch protection applies; it never changes repository settings, secrets or workflow files; it can't open or approve pull requests unless the repository allows it, and its approvals never count; and a run whose code came from an agent acts as that agent. Sandboxes get a similar token starting with `dst_` (see [Sandboxes](#sandboxes)). See [Job tokens and sandbox tokens](https://diffinery.com/docs/accounts/permissions#job-tokens-and-sandbox-tokens) and [Secrets and variables](https://diffinery.com/docs/actions/secrets-and-variables). ## Branch protection A branch protection rule matches branch names with a pattern such as `main`, `release/*` (one path segment) or `release/**` (any depth), and controls how matching branches can change: whether changes must go through a pull request, how many approvals and which checks are required, whether force pushes, deletion and merge commits are allowed, whether a merge queue is used, and what agents may do. The server enforces the rules for every way a branch can change, whether through `git push`, the REST API, MCP or the web UI. Required checks can be workflow jobs, check runs or commit statuses reported by other tools. When Diffinery Actions reports a check, it alone decides that check; to have another tool decide a required check, a rule binds the check to that reporter. See [Checks and statuses](https://diffinery.com/docs/collaboration/checks-and-statuses). Some protections apply even without any rule: the default branch can't be deleted, and agents can't push to it or merge into it. When several rules match a branch, the rule that names the branch exactly wins over patterns; otherwise the oldest matching rule applies. Repository admins can bypass the rules unless the rule sets **Do not allow administrators to bypass these rules** (`enforceAdmins`). A push by an admin bypasses them on its own. A merge doesn't: an admin has to ask for it explicitly (the **Merge without waiting for requirements (bypass)** button, `"bypass_rules": true` in the API, or `diffinery pr merge --admin`), and the bypass is recorded in the audit log as `pull_request.merge_bypassed`. `"bypass_rules": true` skips unmet rules, and `"bypass_merge_queue": true` skips only a required merge queue. Bypassing merge requirements is for people only, never agents, and never works for a draft or a pull request with conflicts. See [Branch protection](https://diffinery.com/docs/repositories/branch-protection) and [Merge queue](https://diffinery.com/docs/collaboration/merge-queue). ## Pull requests with intent A pull request proposes merging one branch (the head) into another (the base) of the same repository. Pull requests and issues share one number sequence per repository, as on GitHub. Besides a title and a description, every pull request can carry an **intent**: one or two sentences on what the change is meant to achieve, for example "Fix the race in token refresh without changing the public API." The intent is shown at the top of the pull request, included in notification emails and returned by the API, the CLI and MCP, so reviewers, human or AI, can check the diff against the stated goal. It can't be edited after the pull request is opened, and agents should always set it. A pull request can be opened as a **draft**: a draft can't be merged until it is marked ready for review (the **Ready for review** button, `diffinery pr ready`, or `PATCH` with `"draft": false`), and it can be turned back into a draft later. Pull requests are reviewed with **Approve**, **Request changes** or comments, checked by workflow runs and other CI, and merged with a merge commit, a squash or a fast-forward rebase once nothing blocks them. With **auto-merge** turned on, Diffinery merges a pull request by itself as soon as nothing blocks it. See [Pull requests](https://diffinery.com/docs/collaboration/pull-requests) and [Issues](https://diffinery.com/docs/collaboration/issues). ## Actions Diffinery Actions runs GitHub Actions workflows from `.github/workflows/` (or `.diffinery/workflows/`) on Cloudflare. Most existing workflow files run unchanged; differences are listed in [Compatibility with GitHub Actions](https://diffinery.com/docs/actions/compatibility). ### Runs, jobs and steps | Term | Meaning | | --- | --- | | Workflow | A YAML file that says when to run (`on:`) and what to run (`jobs:`). | | Event | What starts a workflow: a push, a pull request update, a merge queue group, a manual dispatch, a schedule, another workflow's run, a published release or a `repository_dispatch` API call. | | Run | One execution of one workflow for one event, with a number, a status and a conclusion. | | Job | A set of steps that runs on one runner. Jobs run in parallel unless linked with `needs`; a matrix expands one job into several. | | Step | One command (`run:`) or one action (`uses:`), run in order in the job's workspace. | | Check | The result of one job, reported on the commit as ` / `, for example `CI / test`. Branch protection can require it. | | Environment | A deployment target such as `production`, with its own secrets, variables and branch policy. A job with `environment:` gets them only if the policy allows the ref. | Runs are orchestrated durably, so they survive platform restarts, and a job can run for at most 6 hours. See [Actions overview](https://diffinery.com/docs/actions/overview), [Workflow syntax](https://diffinery.com/docs/actions/workflow-syntax) and [Events that trigger workflows](https://diffinery.com/docs/actions/events). ### Runners A runner is the machine that executes one job. You pick one per job with `runs-on`: - **Hosted runners** run each job in a fresh Ubuntu 24.04 container on Cloudflare. `runs-on: ubuntu-latest` and similar labels use them. - **Self-hosted runners** run jobs on a machine you control, such as a Mac, a GPU box or a server on a private network. You start one with `diffinery runner`, and jobs with `runs-on: self-hosted` (plus any other labels) go to it. See [Runners](https://diffinery.com/docs/actions/runners). ## Checks and commit statuses A check is a pass or fail result attached to a commit. Diffinery Actions reports one check per job. Other tools report results over the GitHub-compatible REST API, either as **commit statuses** (a state and a context name, such as `ci/external`) or as **check runs**. All of them appear together on the commit and the pull request, and branch protection can require any of them by name. See [Checks and statuses](https://diffinery.com/docs/collaboration/checks-and-statuses). ## Releases A release marks a tag as a version you ship, with a title, Markdown release notes and downloadable files (assets, up to 100 MB each). Releases can be drafts or pre-releases, one of them is the latest, and notes can be generated from the merged pull requests. Each release page also links to source archives of its tag. Publishing a release starts `on: release` workflows and sends a `release` webhook. Manage releases at `https://diffinery.com/acme/website/releases`, with the REST API or with the MCP release tools. See [Releases](https://diffinery.com/docs/collaboration/releases). ## Environments and deployments An environment, such as `staging` or `production`, groups the secrets and variables a deployment needs with a policy for which branches and tags may deploy to it. A workflow job that names an environment (`environment: production`) creates a deployment, gets that environment's secrets and variables, and is refused if the policy doesn't allow its ref. Environment secrets never reach pull request runs. Tools outside Actions can record deployments and their status through the REST API, as on GitHub. Environments are managed with the REST API by repository admins. See [Environments](https://diffinery.com/docs/actions/environments). ## Sandboxes A sandbox is a short-lived Linux container with a repository already cloned into it, which you drive over MCP or the REST API: run shell commands, read and write files, and push with Git. Agents use sandboxes to build and test changes without a machine of their own. Creating a sandbox needs write access. Inside it, Git authenticates as whoever created it with at most `write`, so branch protection, push protection and agent guardrails apply to its pushes like any other. A sandbox stops after 30 minutes without calls and keeps no files, so commit and push what you want to keep. GitHub has no built-in equivalent. See [Sandboxes](https://diffinery.com/docs/agents/sandboxes). ## Push protection Every `git push` is scanned for leaked credentials such as API keys and private keys, and so is every commit made without Git: in the web editor, through the REST API (`POST /repos/{owner}/{repo}/diffinery/commits` and the contents and git data APIs) and with the MCP `commit_files` tool. A push or commit that contains one is rejected and nothing from it is stored. A repository admin who is a person can push anyway with `git push -o allow-secrets=`, or commit through the commits API with `allow_secrets`, which is recorded and emailed. See [Push protection](https://diffinery.com/docs/security/push-protection) and [Security overview](https://diffinery.com/docs/security/overview). ## Audit log The audit log is an append-only record of security-relevant actions: sign-ins, passkey and token changes, repository settings (whether changed on the web or through the API), pushes, force pushes, merges, push protection decisions and package changes. When an agent acts, the entry names both the agent and the account it acts for. Only site administrators can view it, under **Settings → Audit log**, which shows the 200 most recent entries. See [Audit log](https://diffinery.com/docs/security/audit-log). ## Notifications Diffinery tells you about activity in the notifications list (the bell in the header, `/notifications`) and by email, following GitHub's rules: you hear about issues and pull requests you take part in, everything in repositories you watch with **All activity**, and failed workflow runs you started. Security emails, such as a new token or a new sign-in, are always sent. Each repository has a **Watch** menu (**Participating and @mentions**, **All activity**, **Ignore**), each issue and pull request a **Subscribe** button, and **Settings → Notifications** turns each group on or off. Agents have no notification settings. See [Notifications](https://diffinery.com/docs/accounts/notifications). ## Where to go next - [Quickstart](https://diffinery.com/docs/quickstart): try these concepts end to end in about 15 minutes. - [Releases](https://diffinery.com/docs/collaboration/releases), [Environments](https://diffinery.com/docs/actions/environments) and [Checks and statuses](https://diffinery.com/docs/collaboration/checks-and-statuses). - [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github): import repositories or whole organizations, link your GitHub account, and set secrets again. - [REST API](https://diffinery.com/docs/reference/rest-api), the [CLI reference](https://diffinery.com/docs/reference/cli) and the [MCP tool reference](https://diffinery.com/docs/reference/mcp-tools). - [Limits](https://diffinery.com/docs/reference/limits): sizes, timeouts and quotas in one place. --- # Guides > Short, task-focused guides to common jobs on Diffinery: moving GitHub Actions workflows, faster CI, AI coding agents with guardrails, and trying Diffinery CI from GitHub. Source: https://diffinery.com/docs/guides Each guide answers one question in a few steps and links to the pages that cover the details. | Guide | What it covers | | --- | --- | | [Move your GitHub Actions workflows to Diffinery](https://diffinery.com/docs/guides/move-github-actions-workflows) | What runs unchanged, runner labels and sizes, marketplace actions, secrets, caches, Docker, OIDC, environments, self-hosted runners for macOS, Windows and Arm, and a checklist. | | [Make your CI faster on Diffinery](https://diffinery.com/docs/guides/faster-ci) | Runner sizes and automatic sizing, caching, setup and Docker head starts, matrices, cancelling superseded runs, and measured numbers. | | [Give an AI coding agent its own account, with guardrails](https://diffinery.com/docs/guides/ai-agent-with-guardrails) | Create an agent and its token, what the server enforces, connecting Claude Code, Codex or any MCP client, reviewing and merging agent pull requests, and auditing what agents did. | | [Run Diffinery CI while your code stays on GitHub](https://diffinery.com/docs/guides/mirror-from-github) | Mirror every GitHub push to Diffinery, copy the secrets your workflows need, and fail on GitHub when Diffinery's runs fail. | Other task pages: [Quickstart](https://diffinery.com/docs/quickstart), [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github), [Deploy to Cloudflare Workers](https://diffinery.com/docs/actions/deploy-to-cloudflare-workers), [Merge on green automatically](https://diffinery.com/docs/collaboration/merge-on-green) and [Cloud agent environments](https://diffinery.com/docs/connect/cloud-agents). --- # Move your GitHub Actions workflows to Diffinery > Run your existing .github/workflows files on Diffinery: what runs unchanged, runner labels and sizes, secrets, caches, Docker, OIDC, environments, and what to change. Source: https://diffinery.com/docs/guides/move-github-actions-workflows Most GitHub Actions workflows run on Diffinery without changes: Diffinery reads `.github/workflows/*.yml`, supports the same triggers, expressions, matrices, `needs`, caches, artifacts, secrets, OIDC and Docker, and downloads marketplace actions from GitHub as they are. Jobs with `runs-on: ubuntu-latest` run on hosted Ubuntu 24.04 runners with 4 vCPUs and 12 GiB of memory by default. What you change is usually small: set your secret values again (GitHub never reveals them), move Windows, macOS and Arm jobs to self-hosted runners, and give `GITHUB_TOKEN` the `permissions:` it needs. ## Steps 1. **Bring the repository over.** Import it under **Settings → Imports → Import from GitHub**, or run `diffinery migrate github acme/website --to acme/website`. The importer copies the history (workflow files included), issues, pull requests, branch protection, Actions variables, environments and the names of your secrets. The import starts no workflow runs; your first push does. See [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github). 2. **Set your secret values.** The import lists every secret name, but never a value. A person who is a repository admin enters each one: **Set secret values** on the import's page, `diffinery secret set NPM_TOKEN -R acme/website`, or the REST API. Do this before your first push, because that push starts the workflows. See [Set secret values](https://diffinery.com/docs/migrate-from-github#set-secret-values). 3. **Check the workflow files.** Run `diffinery workflow validate .github/workflows/ci.yml` on each file. Errors fail the file; warnings name keys that are accepted but ignored. 4. **Fix `runs-on` where needed.** `ubuntu-*` labels run on hosted runners. Windows, macOS and Arm jobs need a self-hosted runner (see [Runners and runner sizes](#runners-and-runner-sizes)). 5. **Add `permissions:` where a job writes.** In repositories created on Diffinery, imported ones included, the job token can only read code and packages by default. A job that comments, labels, pushes, tags or publishes needs a `permissions:` block, for example `contents: write` or `pull-requests: write`, or an admin sets the repository default to write. See [Workflow permissions](https://diffinery.com/docs/actions/workflow-permissions). 6. **Push a commit and watch the first runs** on the **Actions** tab, or with `diffinery run list` and `diffinery run watch `. Fix what fails using the sections below. ## What runs unchanged - **Triggers:** `push`, `pull_request`, `pull_request_target`, `merge_group`, `workflow_dispatch`, `schedule`, `workflow_run`, `release`, `repository_dispatch` and `workflow_call`. See [Events that trigger workflows](https://diffinery.com/docs/actions/events). - **Workflow syntax:** expressions and contexts, matrices with `include` and `exclude`, `needs`, job outputs, `if` conditions, `concurrency`, job summaries, environment files and workflow commands. See [Workflow syntax](https://diffinery.com/docs/actions/workflow-syntax). - **Reusable workflows**, as long as they live on the same Diffinery instance and the calling job has no matrix. See [Reusable workflows](https://diffinery.com/docs/actions/reusable-workflows). - **Workflows in `.github/workflows/`.** Diffinery also reads `.diffinery/workflows/`, for workflows that should only run on Diffinery. ## Runners and runner sizes | `runs-on` | On Diffinery | | --- | --- | | `ubuntu-latest`, `ubuntu-24.04`, `ubuntu-22.04`, any other `ubuntu-*` label, `linux`, `x64` | A hosted Ubuntu 24.04 x64 container, fresh for each job | | `diffinery-tiny`, `diffinery-small`, `diffinery-medium`, `diffinery-large` | A hosted runner of that size | | `windows-*`, `macos-*` | Fails: there are no Windows or macOS hosted runners | | `ubuntu-24.04-arm` and other Arm labels | Runs on the same x64 image; there are no hosted Arm runners | | `[self-hosted, ...]` | A machine you connect with `diffinery runner`, matched on every label | A job without a size label gets the **large** size (4 vCPU, 12 GiB of memory, 20 GB of disk), unless its own earlier runs show that a smaller size serves it just as well. Add a label such as `runs-on: [ubuntu-latest, diffinery-small]` to pin a size. See [Runner sizes](https://diffinery.com/docs/actions/runners#runner-sizes). The hosted image is smaller than GitHub's. It has Git, Git LFS, curl, jq, build-essential, Python 3.12, Node.js 22 with npm, pnpm and yarn, Docker and `gh`. Go, Java, Ruby, Rust, .NET, PowerShell, browsers and cloud CLIs aren't preinstalled: install them with a setup action or `apt-get`. The apt package lists are removed, so run `apt-get update` before `apt-get install`. See [The Ubuntu 24.04 image](https://diffinery.com/docs/actions/runners#the-ubuntu-2404-image). **macOS, Windows, Arm and GPU jobs** run on a [self-hosted runner](https://diffinery.com/docs/actions/runners#self-hosted-runners): a repository admin creates a registration token, and you start `diffinery runner` on your machine with labels such as `--labels macos,arm64`. Jobs with `runs-on: [self-hosted, macos, arm64]` then go to it. On Windows, the documented route is to run the runner inside WSL 2. See [macOS, Windows and GPU machines](https://diffinery.com/docs/actions/runners#macos-windows-and-gpu-machines). ## Marketplace actions Any `uses: owner/repo@ref` is downloaded from GitHub when the step runs, so marketplace actions keep working. JavaScript actions (they run on the runner's Node.js 22), composite actions and Docker container actions are all supported. - `actions/checkout`, `actions/setup-node`, `actions/setup-python`, `actions/setup-go`, `actions/cache`, `actions/upload-artifact` and `actions/download-artifact` are built into the runner for speed, for the version ranges listed in [Built-in actions](https://diffinery.com/docs/actions/compatibility#built-in-actions). For other versions or inputs, the real action runs. - `actions/github-script` works with the REST API (`github.rest.*`); `github.graphql` doesn't, because the job token can't use Diffinery's GraphQL API yet. - Actions in **private GitHub repositories** can't be downloaded on hosted runners. Move them into a Diffinery repository and use them as local actions. See [Actions stored on Diffinery](https://diffinery.com/docs/actions/compatibility#actions-stored-on-diffinery). - `uses: acme/my-action@v1` always means the repository on GitHub, not on Diffinery. ## Secrets and variables - **Values come from people.** The importer copies repository variables with their values, and only the **names** of repository, environment and organization secrets. A repository admin who is a person sets each secret's value. Agents can't set secrets or variables anywhere. - **Where to set them:** repository secrets on **Settings → Secrets and variables** or with `diffinery secret set`; organization secrets with `diffinery secret set NAME --org acme`; environment secrets with the REST API. - **Pull request runs get secrets.** Every pull request comes from a branch of the same repository (there are no forks), so `pull_request` runs receive the repository's secrets. Runs of code an agent wrote don't, unless an admin allows it. See [Which runs receive secrets](https://diffinery.com/docs/actions/secrets-and-variables#which-runs-receive-secrets). - **Tools that encrypt secrets first** (GitHub's sealed-box `encrypted_value`) don't work: send the plain `value` over HTTPS; it's encrypted at rest. See [Secrets and variables](https://diffinery.com/docs/actions/secrets-and-variables). ## Caches and artifacts `actions/cache`, `actions/upload-artifact` and `actions/download-artifact` work as on GitHub, and the built-in versions share their storage and formats with the official actions. Caches are scoped per ref with the same fallbacks to the base branch and the default branch, each repository keeps up to 10 GB of caches, and artifacts are kept for up to 90 days. The `cache` input of the setup actions works too. See [Caching and artifacts](https://diffinery.com/docs/actions/caching-and-artifacts). ## Docker Job containers, service containers, Docker container actions, `docker build`, `docker run` and `docker compose` work on hosted runners, and so do `docker/setup-buildx-action`, `docker/login-action` and `docker/build-push-action`. The Docker daemon starts on first use, and Docker Hub images are pulled through the `mirror.gcr.io` mirror. If you publish images to `ghcr.io`, push them to the registry at `diffinery.com` instead, signed in with the job's `GITHUB_TOKEN` and `packages: write`. See [Docker in workflows](https://diffinery.com/docs/actions/docker) and [Migrating from ghcr.io](https://diffinery.com/docs/packages/container-registry#migrating-from-ghcrio). ## OIDC OIDC works with `permissions: id-token: write`, with `https://diffinery.com` as the issuer. In your cloud provider's trust policy, change the issuer host from `token.actions.githubusercontent.com` to `diffinery.com`, and keep your `sub` patterns unless they rely on a customized subject template. See [OpenID Connect (OIDC)](https://diffinery.com/docs/actions/oidc#differences-from-github). ## Environments The importer creates your environments with their deployment branch policies and variables, and lists their secret names. Then: - Set environment secrets with the REST API, as a repository admin who is a person. See [Environments and their secrets](https://diffinery.com/docs/migrate-from-github#environments-and-their-secrets). - Set required reviewers and wait timers again under **Settings → Environments**, with Diffinery people. They don't come across. See [Required reviewers and wait timers](https://diffinery.com/docs/actions/environments#required-reviewers-and-wait-timers). - Pull request runs never get environment secrets. Keep production credentials in an environment limited to protected branches. ## What doesn't work The full list, with error messages, is in [Compatibility with GitHub Actions](https://diffinery.com/docs/actions/compatibility). The differences you're most likely to meet: - No hosted Windows, macOS or Arm runners, no larger runners above 4 vCPU and no runner groups (`group` is ignored). - Events other than the ten listed above (`issues`, `issue_comment`, `pull_request_review` and the rest) parse but never start a run. - A matrix on a job that calls a reusable workflow isn't supported yet. - `github.graphql` in `actions/github-script` fails. - Problem matchers aren't supported, and annotations show in the job log only. - The `cmd` shell isn't supported, and hosted runners have no PowerShell. - Hard-coded `github.com` and `api.github.com` URLs point at GitHub: use `${{ github.server_url }}` and `${{ github.api_url }}`. ## Checklist 1. Import the repository (or push it) and read the import's warnings. 2. Set every secret value listed by the import, including environment and organization secrets. 3. Run `diffinery workflow validate` on every workflow file. 4. Replace `windows-*`, `macos-*` and Arm labels with `[self-hosted, ...]` labels and start a runner, or move the job to Linux. Check `matrix.os` values used in `runs-on`. 5. Add `apt-get update` before `apt-get install`, and install tools the hosted image doesn't have. 6. Add `permissions:` to jobs that write with `GITHUB_TOKEN`. 7. Move actions from private GitHub repositories into Diffinery and use them as local actions. 8. Replace `ghcr.io` with your instance's host (`diffinery.com` here), and hard-coded GitHub URLs with `github.server_url` and `github.api_url`. 9. Update OIDC trust policies to the `https://diffinery.com` issuer. 10. Set environment secrets, required reviewers and wait timers. 11. Check the required check names under **Settings → Branch protection** (they're ` / `, such as `CI / test`). 12. Push and watch the first runs. ## Frequently asked questions ### Do my GitHub Actions workflows run unchanged on Diffinery? Most do. Diffinery reads `.github/workflows/` and supports the same syntax, triggers, expressions, matrices, caches, artifacts, secrets, OIDC and Docker. Jobs that need Windows, macOS or Arm, actions from private GitHub repositories, or `github.graphql` need changes. See [Compatibility with GitHub Actions](https://diffinery.com/docs/actions/compatibility). ### Does Diffinery copy my GitHub secrets? It copies their names, never their values: GitHub doesn't reveal secret values, and the importer doesn't try. A repository admin who is a person sets each value on Diffinery, from the import's **Set secret values** page, the CLI or the API. ### Can I run macOS or Windows jobs on Diffinery? Not on hosted runners: Cloudflare Containers run Linux only. Run them on your own machine with a self-hosted runner (`diffinery runner`) and `runs-on: [self-hosted, ...]` labels. ### Do marketplace actions work on Diffinery? Yes. Diffinery downloads `uses: owner/repo@ref` actions from GitHub when the step runs. JavaScript, composite and Docker container actions are supported. Actions in private GitHub repositories can't be downloaded on hosted runners. ### Can I try Diffinery Actions before I move? Yes. Keep GitHub as the place where people push, and mirror every push to Diffinery with a GitHub workflow, so Diffinery runs your workflows on each commit. See [Run Diffinery CI while your code stays on GitHub](https://diffinery.com/docs/guides/mirror-from-github). --- # Make your CI faster on Diffinery > Speed up workflows on Diffinery Actions: runner sizes and auto-sizing, caching, setup and Docker head starts, matrices, and cancelling superseded runs, with measured numbers. Source: https://diffinery.com/docs/guides/faster-ci On Diffinery, a hosted job gets 4 vCPUs and 12 GiB of memory by default, and the common setup actions are built into the runner, so many workflows are fast without changes. To go further: let CPU-heavy jobs use all four cores, cache dependencies with keys that the default branch saves, use the Node.js and Python versions the image already has, split long jobs into parallel jobs with `needs` and matrices, and turn on cancelling of superseded pull request runs, which is off by default. Every job's log says how much CPU, memory and disk it used, so you can see where the time goes. ## Steps 1. **Read what a job used.** The last lines of each hosted job's log show its usage, for example `Resources: 0.1 of 4 vCPUs busy on average (0.3 at the 95th percentile), peak memory 0.3 GiB of 12.0 GiB, peak disk 1.6 GB of 19.3 GB`, and a line near the top names the runner size it got and why. The jobs API returns the same as `usage` and `runner_size`. 2. **Keep CPU-heavy jobs on the large size.** It's the default, and automatic sizing keeps builds and test suites there. Pin it with `runs-on: diffinery-large` if you want to be sure (see [How runner sizing works](#how-runner-sizing-works)). 3. **Cache dependencies** with the `cache` input of the setup actions or with `actions/cache`, keyed on your lock file (see [Caching](#caching)). 4. **Use the toolchains the image has**, and let Go, Java and Docker start early (see [Setup actions and head starts](#setup-actions-and-head-starts)). 5. **Run jobs in parallel.** Split a long job into jobs that `needs` only what they depend on, and spread tests over a matrix (see [Matrices and parallel jobs](#matrices-and-parallel-jobs)). 6. **Stop runs nobody will look at.** Add a `concurrency` group that cancels a pull request's older runs, and path filters for changes that don't need CI (see [Cancel superseded runs](#cancel-superseded-runs)). 7. **Re-run only what failed.** **Re-run failed jobs** on the run page (or `diffinery run rerun --failed`) runs the failed jobs and the jobs that depend on them, and keeps the rest from the earlier attempt without starting a runner. See [Re-run a run](https://diffinery.com/docs/actions/overview#re-run-a-run). ## How runner sizing works Hosted runners come in four sizes. Every size runs the same Ubuntu 24.04 image, so a job behaves the same on each. | Size | `runs-on` label | vCPU | Memory | Disk | | --- | --- | --- | --- | --- | | large (default) | `diffinery-large` | 4 | 12 GiB | 20 GB | | medium | `diffinery-medium` | 2 | 8 GiB | 16 GB | | small | `diffinery-small` | 1/2 | 4 GiB | 8 GB | | tiny | `diffinery-tiny` | 1/4 | 1 GiB | 4 GB | - **With a size label**, for example `runs-on: [ubuntu-latest, diffinery-small]`, the job gets that size (with several, the largest). - **Without one**, the job gets **large**, unless its own last runs (at least 3 of up to 5) all fit a smaller size with room to spare, including room for bursts onto several cores and for slower hosts. A job that ran out of memory, failed, timed out or got slower on a smaller size goes back to large for its next 20 runs, and re-runs always run on large. So a smaller size is never the reason a job fails or slows down twice. - **Smaller sizes are about cost, not speed.** A job that mostly waits (a deploy, API calls, polling) runs just as fast on a small machine and costs less. A job that computes is fastest on large. Large is the biggest hosted size; there are no larger runners. See [Runner sizes](https://diffinery.com/docs/actions/runners#runner-sizes) and [What hosted jobs cost](https://diffinery.com/docs/actions/runners#what-hosted-jobs-cost-and-keeping-it-low). ## Caching Diffinery's cache service works with the official `actions/cache` and with the built-in version, which downloads an archive in parallel ranges and extracts it while it arrives. The simplest cache is the `cache` input of a setup action: ```yaml - uses: actions/setup-node@v4 with: node-version: 22 cache: pnpm ``` `actions/setup-python` takes `cache: pip` or `pipenv`, and `actions/setup-go` caches by default. For anything else, use `actions/cache` with a key that changes when your lock file does: ```yaml - uses: actions/cache@v4 with: path: ~/.npm key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} restore-keys: | npm-${{ runner.os }}- ``` Things that make caches hit more often: - **Let the default branch save caches.** A run reads entries saved on its own ref, then (for pull requests) the base branch, then the default branch. Entries saved on one feature branch are never visible to another. - **Include a hash of the lock file in the key.** Entries are immutable: a save with an existing key is skipped, so a key that never changes never refreshes. - **Use `save-always: true`** if failing jobs should still save, since the post step saves only after a successful job by default. - **Cache Docker layers** with `cache-from: type=gha` and `cache-to: type=gha` in `docker/build-push-action`, or with `type=registry` in the [container registry](https://diffinery.com/docs/packages/container-registry). `type=gha` in a plain `docker buildx build` step doesn't work, because `run:` steps don't get the cache service credentials. Each repository keeps up to 10 GB of caches, and entries no job restored for 7 days are deleted. See [Caching and artifacts](https://diffinery.com/docs/actions/caching-and-artifacts). ## Setup actions and head starts - **Node.js 22.22.0 and Python 3.12 are preinstalled.** When the version you ask `actions/setup-node` or `actions/setup-python` for is satisfied by them, the step uses them without a download. Any other version is downloaded each time. - **Go and Java start installing as the job begins.** When a job has `actions/setup-go` (v4 to v6) or `actions/setup-java` (v2 to v5, `distribution: temurin`, a major version such as `java-version: 21`), and the version is written in the workflow or comes from `matrix`, `inputs` or `vars`, the runner downloads that toolchain while checkout runs. Versions read from a file (`go-version-file`, `java-version-file`) and jobs that run in a `container:` install the usual way, as the step runs. - **Docker starts early for jobs that use it.** A job with `container:`, `services:`, a `docker://` action, or a step whose `uses:` or `run:` names `docker` gets the Docker daemon started in the background as the job begins. A `docker` command as the job's very first step waits for the daemon to finish starting. - **Other toolchains** (Ruby, Rust, .NET, browsers) aren't in the image and install as their step runs, so cache what they download. See [The Ubuntu 24.04 image](https://diffinery.com/docs/actions/runners#the-ubuntu-2404-image) and [Built-in actions](https://diffinery.com/docs/actions/compatibility#built-in-actions). ## Matrices and parallel jobs Jobs without `needs` between them run at the same time, each in its own container, and a job starts as soon as the jobs it needs have finished. A matrix turns one job into several: ```yaml jobs: test: runs-on: ubuntu-latest strategy: matrix: shard: [1, 2, 3, 4] steps: - uses: actions/checkout@v4 - run: npm ci - run: npm test -- --shard=${{ matrix.shard }}/4 ``` - An account runs up to 20 hosted jobs at once by default, across all its repositories; further jobs wait in line, oldest first. If a large matrix often waits, cap it with `strategy.max-parallel`. - A matrix may produce at most 256 jobs, and a run at most 1,000. - With `fail-fast` (the default), one failed leg cancels its unfinished siblings, so you hear about a failure sooner. See [strategy](https://diffinery.com/docs/actions/workflow-syntax#strategy) and [Limits](https://diffinery.com/docs/reference/limits). ## Cancel superseded runs As on GitHub, a new push to a pull request doesn't cancel the run for the commit before it. Diffinery doesn't turn this on for you, because cancelling can cut off a deploy halfway or turn an older commit's checks into "cancelled". To opt in for pull requests only, add this to the workflow: ```yaml concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} ``` Older runs of the same pull request are cancelled when a new commit arrives, and runs on your default branch finish. A run on a protected branch is only ever cancelled by runs on that same branch. See [Concurrency](https://diffinery.com/docs/actions/overview#concurrency). To skip runs entirely for changes that don't need them, use path filters on `push` and `pull_request`, for example `paths-ignore: ["docs/**", "**.md"]`. A job that doesn't run reports no check, and a required check that never reports shows as `required check '' has not run`, so be careful with path filters on workflows whose checks are required. See [Path filters](https://diffinery.com/docs/actions/events#path-filters) and [Status checks](https://diffinery.com/docs/actions/overview#status-checks-on-commits-and-pull-requests). ## Measured numbers From Diffinery's measurements on its production hosted runners on October 16, 2026 (see [How fast Diffinery Actions runs, measured](https://diffinery.com/performance) for the method). Ranges are wide because Cloudflare places containers on hosts whose cores differ about 2x in speed. | Stage | Time | | --- | --- | | Push to first job running | 6 to 8 s | | Job queued to first step | About 3 to 5 s | | `actions/checkout` | 1 to 3 s | | Restore a 216 MB pnpm cache | 3 to 4 s on fast hosts, about 10 s on the slowest | | `pnpm install` from that cache | 3 to 7 s | | Upload a 200 MB artifact | 7 to 9 s | | `setup-python`, `setup-node` (preinstalled versions) | 0 s and 2 s | | `setup-go`, `setup-java` (Temurin) | 1 to 3 s and 2 to 5 s | | First `docker` command after checkout | 0.03 to 0.3 s | | First `docker` command as a job's very first step | 1.4 to 2.3 s | The same lint job (checkout, `npm ci`, eslint, prettier and `tsc` on 40 files) took 9 to 14 s on large, 10 to 13 s on medium, 13 to 14 s on small and 15 to 27 s on tiny. A job that only made ten REST requests took 4 seconds on both tiny and large. Diffinery's own pull requests run 10 required checks, including seven end-to-end suites, in about 3 minutes, and up to about 6 minutes on the slowest hosts. ## Frequently asked questions ### What hardware do Diffinery's hosted runners have? By default, 4 vCPUs, 12 GiB of memory and 20 GB of disk, running Ubuntu 24.04 on x64 in a fresh container for each job. Smaller sizes (2, 1/2 and 1/4 vCPU) are picked per job from its own measured runs, or with a `diffinery-*` label. ### Does Diffinery cancel superseded workflow runs automatically? No. As on GitHub, older runs keep running unless the workflow has a `concurrency` group with `cancel-in-progress`. Add one with `cancel-in-progress: ${{ github.event_name == 'pull_request' }}` to cancel older pull request runs and leave default-branch runs alone. ### Can I get a runner bigger than 4 vCPUs? Not as a hosted runner: large (4 vCPU, 12 GiB) is the biggest size. For bigger machines, GPUs or long-lived caches, connect your own machine as a [self-hosted runner](https://diffinery.com/docs/actions/runners#self-hosted-runners). ### Why did my job get a smaller runner? Its last runs all fit a smaller size with room to spare, so Diffinery picked it to save cost. The log's `Runner size:` line says which runs it was based on. If a smaller size ever makes the job fail or slower, it goes back to large for its next 20 runs. Pin `runs-on: diffinery-large` to keep it on large. --- # Give an AI coding agent its own account, with guardrails > Create an agent account for Claude Code, Codex or any MCP client on Diffinery, connect it, and let the server keep a person in charge of protected branches, merges and secrets. Source: https://diffinery.com/docs/guides/ai-agent-with-guardrails On Diffinery, an AI coding agent gets an account of its own, separate from yours: you create it under **Settings → Agents**, give it a token (or let Claude Code or Codex sign in as it through the browser), and its commits, pull requests and comments show as the agent's, on your behalf. The server holds it to guardrails whatever tool it uses: it can't push to or merge into the default branch or protected branches, its pull requests need a person's approval, its own approvals and check results never count, and runs of the code it writes get none of your repository or organization secrets. Repository admins relax these rules, per branch or per repository, when you're ready, for example to let its pull requests merge by themselves once CI passes and a person approves. ## Steps 1. **Create the agent.** Go to **Settings → Agents**, enter an **Agent username** (for example `review-bot`), choose the **Owner** (you, or an organization where you're an owner or admin) and keep the **Maximum role** at **Write**. Click **Create agent**. Only people can create agents, and an organization's agent can reach only that organization's repositories. 2. **Create a token for it**, unless the agent will sign in through the browser (step 4). In the agent's row, open **Create a token for review-bot**, keep the **Scope** at **Write**, choose the **Days** (1 to 366), and click **Create token**. Copy it: it's shown once. Give it to the agent as an environment variable such as `DIFFINERY_TOKEN`, never in a file you commit. See [Tokens for agents](https://diffinery.com/docs/agents/overview#tokens-for-agents). 3. **Protect the default branch.** Under the repository's **Settings → Branch protection**, add a rule for `main` with **Require a pull request before merging**, at least one **Required approvals**, and your CI checks under **Required status checks**. Agents can't push to the default branch either way; the rule makes sure every change is reviewed and tested. See [Branch protection](https://diffinery.com/docs/repositories/branch-protection). 4. **Connect the agent** (see [Connect Claude Code, Codex or another MCP client](#connect-claude-code-codex-or-another-mcp-client)). 5. **Tell it how to work**, for example in your agent instructions file: work on a new branch, open a pull request with an `intent` that states the goal, wait for checks with `diffinery pr checks --watch`, and fix failures before asking for review. 6. **Review and merge its pull requests**, by hand or with merge on green (see [Review and merge agent pull requests](#review-and-merge-agent-pull-requests)). ## What the server enforces These rules hold for Git pushes, the REST API, MCP tools and sandboxes alike, whatever the agent's role: | Rule | What it means | | --- | --- | | Never more access than its owner | Its role is the lowest of its maximum role (write by default), its owner's role on the repository and its token's scope. | | No pushes to the default branch or protected branches | Pushes and commits there fail with `agents may not push to protected or default branches; open a pull request`. It pushes other branches freely. | | No merges into the default branch or protected branches | The merge blocker reads `agents may not merge into this branch; a human must merge`. | | A person approves its pull requests | At least one approval from a person, even on a branch with no rule. An agent's approval never counts; its requested changes still block. | | Its check results don't count | Commit statuses and check runs an agent reports never satisfy a required check, so it can't mark its own work as passing. | | No secrets for runs of its code | A workflow run whose code came from an agent gets no repository or organization secrets, only its job token, and its token is held to the same rules. Environment secrets reach it only from environments limited to protected branches, and never on pull request refs. | | No settings that guard the repository | It can't change branch protection, secrets, variables or environments, dismiss reviews, delete or transfer repositories, or create other agents. | | No push protection bypass | A push or commit containing something that looks like a credential is always refused. | | Stamped commits | Commits Diffinery writes for it carry a `diffinery-agent review-bot on-behalf-of diffy` header. | The full table, with how to relax each rule, is in [Guardrails](https://diffinery.com/docs/agents/overview#guardrails). ## Connect Claude Code, Codex or another MCP client Every app connects to the same MCP server, `https://diffinery.com/mcp`. Apps with browser sign-in need no token: on Diffinery's consent page, choose to **act as** your agent, and Write access. - **Claude Code:** install the CLI and run `diffinery setup`, which adds the Diffinery plugins. Then run `/mcp`, select **plugin:diffinery:diffinery**, choose **Authenticate**, and pick the agent on the consent page. See [Claude Code](https://diffinery.com/docs/connect/claude-code). - **Codex:** run `diffinery setup`, add the Diffinery plugin, then run `codex mcp login diffinery` and pick the agent on the consent page. See [Codex](https://diffinery.com/docs/connect/codex). - **Cursor, VS Code and other MCP apps:** add `https://diffinery.com/mcp` as a remote HTTP server and sign in. See [Other apps](https://diffinery.com/docs/connect/other-apps). - **Headless (CI, scripts, scheduled jobs):** send the agent's token instead. For Claude Code: ```sh claude mcp add --scope user --transport http diffinery https://diffinery.com/mcp \ --header 'Authorization: Bearer ${DIFFINERY_TOKEN}' ``` `diffinery mcp-config` prints a snippet for other clients. See [Headless use](https://diffinery.com/docs/connect/how-sign-in-works#headless-use). - **Git and the CLI:** with `DIFFINERY_TOKEN` set, `diffinery auth setup-git` lets Git push with it, and `diffinery auth setup-gh` makes `gh pr create` and `gh pr checks` work against Diffinery. See [GitHub CLI](https://diffinery.com/docs/agents/github-cli). Ask the agent "Who am I on Diffinery?" to check: the `whoami` tool answers with the agent's login. **Cloud environments.** For a Claude Code cloud environment, or any other agent sandbox, open the repository's **Settings → Agent setup** and choose **Generate agent token**. It makes an agent that can reach only that repository and gives you the allowed domain, a one-line setup script and the environment variables to paste. A **Check** turns green once a session has set itself up. See [Cloud agent environments](https://diffinery.com/docs/connect/cloud-agents). ## Review and merge agent pull requests - **Find what needs you.** [Today](https://diffinery.com/docs/agents/today), the first page after signing in, lists **Agent PR needs a person's approval** for agent pull requests no person has approved at their latest commit. - **Read the intent first.** Every pull request can carry an `intent`, one or two sentences on what the change is meant to do, shown at the top so you can check the diff against it. See [Pull requests](https://diffinery.com/docs/collaboration/pull-requests). - **Approve, then merge.** You (or anyone with write access other than the agent) approve. The agent's owner can approve, because the owner is a different account from the agent. - **Let it merge on green.** An admin opens the repository's **Settings → Merge on green**, ticks the checks that must pass and the agents, and chooses whether agents' pull requests merge **Once the checks pass and a person approved** or **As soon as the checks pass**. Each agent pull request then merges by itself when its conditions are met. See [Merge on green automatically](https://diffinery.com/docs/collaboration/merge-on-green). - **Or allow auto-merge per branch.** **Allow agents to land pull requests through auto-merge** on a branch's rule (with at least one required check) lets the agent turn on auto-merge for its own pull requests (`enable_auto_merge` over MCP, or `diffinery pr merge --auto`). Diffinery merges once every rule is met; if the agent pushes again, a person approves again. See [Agents landing changes](https://diffinery.com/docs/repositories/branch-protection#agents-landing-changes). - **Workflow changes always need a person.** A pull request that adds, changes or deletes a workflow file never lands through an agent's auto-merge: CI can't vouch for a change to itself. - **Plan for deploys after agent merges.** A merge that auto-merge makes for an agent is the agent's push, so later runs on that branch are runs of agent code and get no repository or organization secrets. Keep deploy credentials in an environment limited to protected branches, or have an admin turn on **Give runs of agent code the repository's and organization's secrets**. See [Which runs receive secrets](https://diffinery.com/docs/actions/secrets-and-variables#which-runs-receive-secrets). To have one of your agents review pull requests for bugs before you do, turn on [Agent review](https://diffinery.com/docs/agents/review). To give an agent a goal and get a pull request back, see [Agent tasks](https://diffinery.com/docs/agents/tasks). ## Audit what agents did - **On every item:** agents have an `agent` badge and `on behalf of ` next to their name on pull requests, reviews, comments and workflow runs, and the API returns `"type": "Bot"` for them. - **In Git:** commits Diffinery writes for an agent carry the `diffinery-agent ... on-behalf-of ...` header, covered by the commit's SHA. See it with `git cat-file -p `. - **Its tokens:** **Settings → Agents** lists each agent's tokens with their scope and last use, and a **revoke** link. Diffinery sends a security email when an agent or an agent token is created. - **The audit log:** site administrators see every audited action under **Settings → Audit log**, with the agent as the actor and its owner alongside (`review-bot for diffy`). See [Audit log](https://diffinery.com/docs/security/audit-log). - **Cut it off:** revoke one token to stop one running copy, or **Disable** the agent under **Settings → Agents** to revoke all its tokens at once. ## Frequently asked questions ### Can an AI agent push to main on Diffinery? Not by default. Agents can't push to the default branch or to any protected branch; they push a branch and open a pull request. A repository admin can allow it on a branch's protection rule with **Allow agents to push directly**. ### Can an agent approve or merge its own pull request? An agent's approval never counts toward required approvals, and agents can't merge into the default branch or protected branches. A person approves its pull request. A repository admin can let agents land approved pull requests through auto-merge, so CI and a person decide rather than the agent, or waive the approval so green required checks are enough. ### Can an agent read my repository secrets? Agents can't create, change or delete secrets, and a workflow run of code an agent wrote gets no repository or organization secrets unless a repository admin turns that on. Environment secrets reach such a run only from environments limited to protected branches, and never on pull request refs. Agents with write access can read Actions variables, which aren't secret. ### Which AI coding agents work with Diffinery? Any agent that uses Git, the GitHub CLI, the REST API or MCP. There are guides for [Claude](https://diffinery.com/docs/connect/claude), [Claude Code](https://diffinery.com/docs/connect/claude-code), [Codex](https://diffinery.com/docs/connect/codex), Cursor and VS Code ([Other apps](https://diffinery.com/docs/connect/other-apps)). ### How do I take away an agent's access? Revoke its token under **Settings → Agents**, or click **Disable** next to the agent to revoke all its tokens at once. An app connected through the browser is disconnected under **Settings → Access tokens → Connected apps**. --- # Run Diffinery CI while your code stays on GitHub > Try Diffinery Actions on your existing workflows without moving: mirror every GitHub push to Diffinery with a GitHub workflow, copy the secrets it needs, and wait for the results. Source: https://diffinery.com/docs/guides/mirror-from-github You can run your GitHub Actions workflows on Diffinery without moving your team off GitHub. A small GitHub workflow pushes every branch and tag to a Diffinery repository on each push, and Diffinery then runs the same `.github/workflows/` files on each mirrored commit. The same workflow can copy the secrets your workflows need straight from GitHub's secret store, and fail on GitHub when the runs on Diffinery fail. Diffinery itself was developed this way. ## Steps 1. **Create the Diffinery repository**, for example `acme/website`, at `https://diffinery.com/new` or with `diffinery repo create website --org acme`. 2. **Create a Diffinery token** with the `admin` scope, for an account that is an admin of that repository, under **Settings → Access tokens**. If force pushes to protected branches should go through, the protection rules must let admins bypass them. 3. **Add it on GitHub** as a repository secret named `DIFFINERY_TOKEN`. 4. **Add the mirror workflow on GitHub** as `.github/workflows/mirror-to-diffinery.yml`. Copy it from [Keep GitHub as upstream and mirror to Diffinery](https://diffinery.com/docs/migrate-from-github#keep-github-as-upstream-and-mirror-to-diffinery), and list in its secrets step every secret your workflows use. 5. **Push to GitHub.** The mirror pushes every branch and tag to Diffinery, and Diffinery starts your workflows on the mirrored commit. Watch them on the repository's **Actions** tab, or with `diffinery run list -R acme/website`. 6. **Optionally, wait for the results on GitHub.** Add the [Wait for Actions on Diffinery](https://diffinery.com/docs/migrate-from-github#wait-for-diffinerys-runs) step, which polls Diffinery's runs for the pushed commit and fails the GitHub job if any of them fail. ## How the mirror behaves - **GitHub wins.** Every GitHub branch is pushed to the branch of the same name with a leading `+`, so changes made directly on Diffinery to mirrored branches are overwritten. - **Deleted branches stay.** Branches deleted on GitHub aren't deleted on Diffinery; delete them there by hand. - **Secrets go straight across.** The secrets step reads each value from GitHub's secret store inside your own workflow and sends it to Diffinery over HTTPS, without printing it. Variables can be copied the same way. - **The mirror doesn't run on Diffinery.** The workflow has an `if: ${{ github.server_url == 'https://github.com' }}` guard, because Diffinery also runs the mirrored copy of the file. - **Push protection still applies.** If a mirrored push is blocked because it contains something that looks like a credential, a repository admin can let it through with `-o allow-secrets=` on the `git push` line. ## Before you rely on the results - **Check what differs.** Windows, macOS and Arm jobs need a self-hosted runner on Diffinery, the job token is read-only by default, and a few features aren't supported. See [Move your GitHub Actions workflows to Diffinery](https://diffinery.com/docs/guides/move-github-actions-workflows) and [Compatibility with GitHub Actions](https://diffinery.com/docs/actions/compatibility). - **Keep Diffinery-only workflows apart.** Put workflows that should run only on Diffinery in `.diffinery/workflows/`, so GitHub doesn't run them, or guard a step with `if: github.server_url == 'https://diffinery.com'`. See [Where workflow files live](https://diffinery.com/docs/actions/overview#where-workflow-files-live). - **Compare speed with your own jobs.** Every hosted job's log ends with what it used and names the runner size it got. See [Make your CI faster on Diffinery](https://diffinery.com/docs/guides/faster-ci). ## When you're ready to move Import the repository with its issues, pull requests, reviews and releases (**Settings → Imports → Import from GitHub**, or `diffinery migrate github`), set its secrets, update everyone's remotes, then archive the GitHub repository or remove the mirror workflow. See [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github). ## Frequently asked questions ### Can I use Diffinery Actions without moving my repository off GitHub? Yes. Mirror every push from GitHub to a Diffinery repository with a GitHub workflow; Diffinery then runs your `.github/workflows/` files on each mirrored commit. People keep pushing and reviewing on GitHub. ### Do I have to re-enter my secrets on Diffinery to mirror? No. The mirror workflow can copy the secrets you list from GitHub's secret store to Diffinery on each run, inside your own workflow, without printing them. You can also set them on Diffinery by hand. --- # Compatibility with GitHub Actions > What works, what works differently and what isn't supported when you run GitHub Actions workflows on Diffinery, with a checklist for porting workflows. Source: https://diffinery.com/docs/actions/compatibility Diffinery runs GitHub Actions workflow files with the same syntax, triggers, expressions and actions, so most workflows run without changes. This page lists every place where Diffinery behaves differently, what happens when a workflow uses something that isn't supported, and a checklist for porting workflows from GitHub. ## At a glance | Area | Status on Diffinery | Details | | --- | --- | --- | | Workflow syntax | Supported, with a few keys accepted but ignored | [Workflow syntax](#workflow-syntax) | | Triggers | `push`, `pull_request`, `pull_request_target`, `merge_group`, `workflow_dispatch`, `schedule`, `workflow_run`, `release`, `repository_dispatch`, `workflow_call` | [Triggers](#triggers) | | Expressions and contexts | Supported, with small differences in values | [Contexts and environment variables](#contexts-and-environment-variables) | | Hosted runners | Linux x64 only (Ubuntu 24.04) | [Runners](#runners) | | Self-hosted runners | Supported, through `diffinery runner` | [Runners](https://diffinery.com/docs/actions/runners) | | Matrices, `needs`, outputs, job summaries | Supported | [Jobs and steps](#jobs-and-steps) | | `actions/checkout`, `actions/setup-node`, `actions/setup-python`, `actions/setup-go` | Built into the runner for speed; the real action runs for versions or inputs the built-in doesn't cover | [Built-in actions](#built-in-actions) | | `actions/cache`, `actions/upload-artifact`, `actions/download-artifact` | Built into the runner, sharing storage and formats with the official actions, which also work | [Caching and artifacts](https://diffinery.com/docs/actions/caching-and-artifacts) | | `actions/github-script` | Supported (the real action runs) | [actions/github-script](#actionsgithub-script) | | Other JavaScript, composite and Docker actions | Supported, downloaded from GitHub, with the cache and artifact runtime services | [Other actions](#other-actions) | | Job containers and service containers | Supported | [Docker in workflows](https://diffinery.com/docs/actions/docker) | | Reusable workflows | Supported, except a matrix on the calling job | [Reusable workflows](https://diffinery.com/docs/actions/reusable-workflows) | | Secrets and variables | Repository, organization and environment secrets and variables | [Secrets and variables](https://diffinery.com/docs/actions/secrets-and-variables) | | Environments | Supported: branch policies, required reviewers (people), wait timers, environment secrets and variables, deployments. | [Secrets, variables and environments](#secrets-variables-and-environments) | | `GITHUB_TOKEN` | Follows `permissions:` per endpoint, as on GitHub; read-only by default in new repositories | [GITHUB_TOKEN and permissions](#github_token-and-permissions) | | OIDC | Supported, with Diffinery as the issuer | [OIDC](https://diffinery.com/docs/actions/oidc) | | Windows and macOS hosted runners | Not available (Cloudflare Containers run Linux only); use self-hosted runners | [Runners](#runners) | ## Workflow files Diffinery reads workflows from `.github/workflows/` and from `.diffinery/workflows/`. Every `.yml` or `.yaml` file directly in either directory is a workflow; files in subdirectories are ignored. Workflows in both directories run, each as its own workflow. Put workflows that should only run on Diffinery in `.diffinery/workflows/`, so a GitHub mirror of the repository doesn't run them. See [Where workflow files live](https://diffinery.com/docs/actions/overview#where-workflow-files-live). Check a workflow before you push it: ```sh diffinery workflow validate .github/workflows/ci.yml ``` Errors fail the file; warnings, such as `unknown job key ''` or `unknown event ''`, are printed but the workflow still runs. ## Triggers | Event | Status | Differences | | --- | --- | --- | | `push` | Supported | `commits` in the payload lists only the pushed head commit. Path filters pass when a push creates a branch. | | `pull_request` | Supported | Activity types `opened`, `synchronize`, `reopened`, `closed`, `edited`, `ready_for_review` and `converted_to_draft` only; the `edited` payload has no `changes` object. No runs while the pull request conflicts with its base. Runs get the repository's secrets, because pull requests come from branches of the same repository. | | `pull_request_target` | Supported | Same activity types as `pull_request`. Runs also while the pull request conflicts. | | `merge_group` | Supported | `checks_requested`. | | `workflow_dispatch` | Supported | `github.event.inputs` keeps the input types instead of turning them into strings. The dispatch API answers `201 Created` with the run instead of `204 No Content`. | | `schedule` | Supported | Checked every 5 minutes, so a schedule starts within about 5 minutes after it's due. Runs have the actor `diffinery-scheduler`. | | `workflow_run` | Supported | Activity types `requested` and `completed` (not `in_progress`), `workflows` is required, and chains go at most 3 levels deep. | | `release` | Supported | Same activity types. No runs for draft releases, as on GitHub. Without `types`, a new published release starts three runs (`created`, `published`, `released`), as on GitHub. Only `types` filters; `branches`, `tags` and `paths` aren't applied. | | `repository_dispatch` | Supported | `POST /repos/{owner}/{repo}/dispatches` answers `204`. The payload has `action`, `branch`, `client_payload`, `repository` and `sender`. | | `workflow_call` | Supported | See [Reusable workflows](https://diffinery.com/docs/actions/reusable-workflows). | | Every other GitHub event (`issues`, `issue_comment`, `pull_request_review`, `create`, `delete`, `status`, `deployment`, `deployment_status` and the rest) | Accepted, never fires | The workflow parses, but Diffinery never starts a run for these events. (Webhooks do get `status`, `deployment` and `deployment_status`.) | | A name that isn't a GitHub event | Warning | `unknown event ''`. | Details for each event are in [Events that trigger workflows](https://diffinery.com/docs/actions/events). ## Workflow syntax Every key of the GitHub Actions workflow syntax parses. These keys behave differently: | Key | What happens on Diffinery | | --- | --- | | `jobs..runs-on` | Supported, including the `matrix` context (`runs-on: ${{ matrix.os }}`), but only Linux labels are hosted. The `group` key is ignored. | | `jobs..environment` | Supported: the branch policy is enforced, the environment's secrets and variables are added and a deployment is recorded. Required reviewers and wait timers hold the job before it starts, and `url` can't use step outputs. See [environment](https://diffinery.com/docs/actions/workflow-syntax#environment). | | `jobs..snapshot` | Accepted and ignored. | | `jobs..timeout-minutes` | Default and maximum 360. Larger values are capped at 360. | | `jobs..strategy.matrix` | At most 256 jobs per matrix, and at most 1,000 jobs in a run, matrix legs and the jobs of called workflows included. | | `jobs..uses` with `strategy.matrix` | Not supported yet. The run fails with `jobs.: a matrix on a job that calls a reusable workflow is not supported yet`. | | `concurrency` (workflow level) | Same as GitHub: one run in progress and at most one waiting per group; a newer run cancels older waiting ones. After 6 hours of waiting a run starts anyway. See [Concurrency](https://diffinery.com/docs/actions/overview#concurrency). | | `defaults.run.shell`, `jobs..steps[*].shell` | `cmd` isn't supported. `pwsh` and `powershell` need PowerShell, which hosted runners don't have. | An unknown key gives a warning such as `unknown job key ''` or `unknown step key ''`, and the key is ignored. The full reference is [Workflow syntax](https://diffinery.com/docs/actions/workflow-syntax). ## Runners | `runs-on` | GitHub | Diffinery | | --- | --- | --- | | `ubuntu-latest`, `ubuntu-24.04`, `ubuntu-22.04` | Hosted Ubuntu VM | Hosted Ubuntu 24.04 container, x64. All three labels get the same image. | | `ubuntu-24.04-arm` and other ARM labels | Hosted ARM runner | No hosted ARM runners. An `ubuntu-*` ARM label runs on the same x64 image as `ubuntu-latest`. For ARM, use `[self-hosted, ...]` labels on an ARM machine. | | `windows-*`, `macos-*` | Hosted Windows or macOS VM | Not available: Cloudflare Containers run Linux only. The job fails with `No Diffinery runner matches runs-on: . Linux (ubuntu-*) runners are hosted; anything else needs runs-on: [self-hosted, ...] and a registered runner.` | | Larger runners and runner groups | Supported | Not available. `group` is ignored. | | `[self-hosted, ...]` | Self-hosted runner | Self-hosted runner started with `diffinery runner`, matched on every label. | What's different about the hosted image: - It's much smaller than GitHub's image. Git, Git LFS, curl, jq, zstd, build-essential, Python 3.12, Node.js 22 with npm, pnpm and yarn, nvm, Docker and the GitHub CLI (`gh`) are preinstalled. `ImageOS` is `ubuntu24`, as on GitHub's `ubuntu-24.04` image. Go, Java, Ruby, Rust, .NET, PowerShell, browsers and cloud CLIs aren't. See [The Ubuntu 24.04 image](https://diffinery.com/docs/actions/runners#the-ubuntu-2404-image). - Jobs run as `root`. `sudo` is installed and needs no password, as on GitHub, so `sudo` in commands keeps working. - The apt package lists are removed. Run `apt-get update` before `apt-get install`. - Every job starts in a fresh container. Nothing carries over between jobs except caches and artifacts. On self-hosted runners, `runner.os` is always `Linux`, and the setup actions download Linux builds, even on a macOS machine. See [Self-hosted runners](https://diffinery.com/docs/actions/runners#self-hosted-runners). ## Jobs and steps These work the same as on GitHub: `needs` (a job starts as soon as the jobs it needs finish), job outputs, `if` conditions, status check functions (a skipped or failed job further up the `needs` chain skips the jobs below it unless their `if` says otherwise), matrices with `include` and `exclude`, `fail-fast`, `max-parallel`, job and step `continue-on-error`, job-level `concurrency`, `timeout-minutes`, `working-directory`, environment files (`GITHUB_OUTPUT`, `GITHUB_ENV`, `GITHUB_PATH`, `GITHUB_STEP_SUMMARY`, `GITHUB_STATE`), workflow commands, job summaries, masking and debug logging with `ACTIONS_STEP_DEBUG` and `ACTIONS_RUNNER_DEBUG`. Differences: | Behaviour | GitHub | Diffinery | | --- | --- | --- | | Default shell for `run` | `bash -e {0}` | `bash --noprofile --norc -eo pipefail {0}`, so a failing command in a pipeline fails the step. | | `::add-matcher::` problem matchers | Turn matching output into annotations | Not supported; the line is printed as is. | | Annotations (`::error file=...`) | Shown on pull request files | Shown in the job log only. | | `::set-env` and `::add-path` | Disabled | Disabled, with the same message. | | `github.run_number` | Counts runs of one workflow | Counts runs of every workflow in the repository. | See [Expressions and contexts](https://diffinery.com/docs/actions/expressions) and [Workflow syntax](https://diffinery.com/docs/actions/workflow-syntax) for the details. ## Built-in actions For speed, the runner has its own implementation of these actions and runs it instead of downloading the action, when the step uses a version tag in the listed range: | Action | Built-in for | | --- | --- | | `actions/checkout` | `v2` to `v6` | | `actions/setup-node` | `v3` to `v7` | | `actions/setup-python`, `actions/setup-go` | `v4` to `v6` | | `actions/cache`, `actions/cache/restore`, `actions/cache/save` | `v3` to `v6` | | `actions/upload-artifact` | `v4` to `v7` | | `actions/download-artifact` | `v4` to `v8` | The built-ins mirror the official actions' inputs, outputs and storage: a cache or artifact saved by a built-in works with the official action and the other way round. A built-in steps aside, and the real action is downloaded from GitHub and run, when: - the reference isn't `vN`, `vN.N` or `vN.N.N` in the range, for example a commit SHA, a branch or a newer major version; - the step passes an input the built-in doesn't list (see the tables below); - an input has a value the built-in doesn't handle: `ssh-key` for checkout, an `architecture` other than the runner's, a `cache` value the built-in doesn't support, a PyPy or GraalPy version, or `update-environment: false` for setup-python; - the workflow, job or step `env:` sets `DIFFINERY_BUILTINS` to `false`, `0`, `no` or `off`; - a self-hosted runner was started with `DIFFINERY_DISABLE_BUILTINS=1`. ```yaml jobs: build: runs-on: ubuntu-latest env: DIFFINERY_BUILTINS: false # this job runs the real actions steps: - uses: actions/checkout@v4 ``` Built-in actions run on the runner, not inside a job container. In a job with `container:`, they work on the shared workspace. ### actions/checkout Checks out a repository on the same Diffinery instance into the workspace. | Input | Default | Notes | | --- | --- | --- | | `repository` | The workflow's repository | `owner/name` of a repository on Diffinery. Anything else fails with `Invalid repository ''. Expected format {owner}/{repo}.` | | `ref` | The commit that triggered the run, or the other repository's default branch | Branch, tag, full ref or 40-character commit SHA. A short SHA is treated as a branch or tag name. | | `token` | The job's token | The job's token reads the workflow's own repository (with `contents: read`) and any public repository on Diffinery. For another private repository, pass a personal or agent token from a secret. The job's token is only ever sent to Diffinery; a different `github-server-url` needs an explicit `token`. | | `fetch-depth` | `1` | `0` fetches all branches and tags with full history. | | `fetch-tags` | `false` | | | `path` | The workspace | Relative to the workspace. A path outside it fails with `Repository path '' is not under ''`. | | `clean` | `true` | Runs `git clean -ffdx` and `git reset --hard HEAD` on an existing checkout. | | `filter` | | A partial clone filter such as `blob:none`, passed to `git fetch`. Diffinery's git server doesn't support partial clone yet and sends everything. | | `sparse-checkout` | | Patterns, one per line. Sets up a sparse checkout and fetches with `filter: blob:none` unless you set `filter`. | | `sparse-checkout-cone-mode` | `true` | `false` uses non-cone patterns. | | `lfs` | `false` | Fetches Git LFS objects for the checked-out commit (and runs `git lfs pull` in submodules). See [Git LFS](https://diffinery.com/docs/repositories/git-lfs). | | `submodules` | `false` | `true` or `recursive`. Submodules on Diffinery are fetched with the same credentials. A failed submodule update fails the step. | | `persist-credentials` | `true` | Writes the token into the repository's local Git config at the end, so later `git` commands authenticate. A post step removes it. With `false`, nothing is written. | | `show-progress` | `true` | Passes `--progress` to `git fetch` and `git checkout`. | | `set-safe-directory` | `true` | Marks the checkout as a Git safe directory for checkout's own commands. | | `github-server-url` | Diffinery | Check out from another server, for example `https://github.com`, with an explicit `token` for private repositories. | | `ssh-key` | | Not handled by the built-in: the real action runs. `ssh-known-hosts`, `ssh-strict` and `ssh-user` are accepted and ignored. | While fetching, the token reaches git through the environment, so a checkout that fails halfway leaves no credentials in `.git/config`. Credentials a reused workspace still holds from another job are removed first. Outputs: `commit` (the checked-out SHA) and `ref`. As on GitHub, a `pull_request` run checks out the test merge commit (`refs/pull//merge`) by default, and a `pull_request_target` run checks out the base branch. Errors: - `Failed to fetch ref '' from /. Check that the ref exists and the token has read access.` - `A branch or tag with the name '' could not be found` (with `fetch-depth: 0`). - `Checked out but expected .` ### actions/setup-node | Input | Notes | | --- | --- | | `node-version` | A version or range (`22`, `20.x`, `>=20.10`), `lts/*`, `lts/`, `lts/-1`, `latest`, `current` or `node`. | | `node-version-file` | `package.json` (reads `volta.node`, then `devEngines.runtime.version`, then `engines.node`), `.tool-versions` (`nodejs` or `node`), or a file whose first non-comment line is the version, such as `.nvmrc` or `.node-version`. | | `check-latest` | Download the newest matching version even when the preinstalled one satisfies the request. | | `registry-url`, `scope`, `always-auth` | Writes an `.npmrc` that reads `NODE_AUTH_TOKEN`, and sets `NPM_CONFIG_USERCONFIG`. For `npm.pkg.github.com` the scope defaults to the repository owner. `always-auth` is written for `v4` and earlier, or when you set it. | | `cache`, `cache-dependency-path` | `npm`, `pnpm` or `yarn`. See [Dependency caching with setup actions](https://diffinery.com/docs/actions/caching-and-artifacts#dependency-caching-with-setup-actions). | | `package-manager-cache` | `v5` and later cache npm automatically when `package.json` names npm as its package manager; `false` turns that off. | | `architecture`, `token` | Accepted. An `architecture` other than the runner's runs the real action. | Hosted runners have Node.js 22.22.0. A request that it satisfies uses it without a download; any other version is downloaded from `nodejs.org` into the tool cache. Without `node-version` or `node-version-file`, the step logs `No node-version specified; using the pre-installed node .` Other inputs, such as `mirror`, run the real action. Outputs: `node-version` (for example `v22.22.0`), `cache-hit` and `cache-primary-key`. ### actions/setup-python | Input | Notes | | --- | --- | | `python-version` | One CPython version or range, such as `3.12`, `3.11.9`, `3.x` or `3.14-dev`. PyPy and GraalPy versions run the real action. | | `python-version-file` | `.python-version`, `.tool-versions` (`python`), `pyproject.toml` (`requires-python`), or a file whose first non-comment line is the version. Without either input, `.python-version` in the workspace is used if present. | | `allow-prereleases` | Falls back to a pre-release build when no stable release matches. A version ending in `-dev` does the same. | | `cache`, `cache-dependency-path` | `pip` or `pipenv`. Other values run the real action. See [Dependency caching with setup actions](https://diffinery.com/docs/actions/caching-and-artifacts#dependency-caching-with-setup-actions). | | `architecture`, `check-latest`, `token`, `update-environment` | Accepted. An `architecture` other than the runner's, or `update-environment: false`, runs the real action. | Hosted runners have Python 3.12. A request that it satisfies uses it. Other versions are installed from the `actions/python-versions` builds that GitHub publishes, and the step sets `pythonLocation`, `Python_ROOT_DIR`, `Python3_ROOT_DIR`, `PKG_CONFIG_PATH` and `LD_LIBRARY_PATH` like the original action. Other inputs, such as `freethreaded`, run the real action. Outputs: `python-version`, `python-path` and `cache-hit`. ### actions/setup-go | Input | Notes | | --- | --- | | `go-version` | A version or range, `stable` or `oldstable`. | | `go-version-file` | `go.mod` or `go.work` (`toolchain` line first, then `go`), `.tool-versions` (`golang` or `go`), or a file whose first line is the version. | | `check-latest` | Download the newest matching version. | | `cache`, `cache-dependency-path` | On by default. Without a `go.sum` in the workspace root, the step warns `Restore cache failed: ...` and continues. | | `architecture`, `token` | Accepted. An `architecture` other than the runner's runs the real action. | Go isn't preinstalled on hosted runners, so the step downloads it from `go.dev`. Without a version on a runner that has no Go, it fails with `No go-version specified and Go is not installed on this runner.` Outputs: `go-version` and `cache-hit`. ### actions/cache and artifacts `actions/cache`, `actions/cache/restore`, `actions/cache/save`, `actions/upload-artifact` and `actions/download-artifact` support the official actions' inputs and outputs, including `retention-days`, `overwrite`, `compression-level`, `archive`, downloading all artifacts, `pattern`, `merge-multiple`, `artifact-ids`, and `run-id` with `github-token`. Caches are scoped per ref as on GitHub, each repository keeps up to 10 GB of caches, and artifacts are zip files kept for up to 90 days. [Caching and artifacts](https://diffinery.com/docs/actions/caching-and-artifacts) has the details. ### actions/github-script `actions/github-script` isn't a built-in: the real action runs, and its `github` client talks to Diffinery's REST API (`GITHUB_API_URL`) with the job token. What it may do follows the job's `permissions:`: ```yaml jobs: label: runs-on: ubuntu-latest permissions: issues: write pull-requests: write steps: - uses: actions/github-script@v7 with: script: | await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, labels: ["needs-review"], }); ``` `github.graphql` fails: Diffinery's [GraphQL API](https://diffinery.com/docs/reference/graphql-api) answers personal and agent tokens, not a job's token. REST calls to endpoints Diffinery doesn't have get a JSON `404 Not Found`. See [the REST API reference](https://diffinery.com/docs/reference/rest-api) for the endpoints Diffinery has. ## Other actions Any other `uses: owner/repo[/path]@ref` (and a built-in action the built-in doesn't cover) is downloaded from GitHub (`codeload.github.com`, or with `git` from `github.com` when that endpoint can't be reached) when the step runs and executed according to its `action.yml` or `action.yaml`. ### JavaScript actions Actions with `runs.using: node12`, `node16`, `node20`, `node24` or any other `node` run with the runner's own Node.js 22, whatever version they ask for. `pre`, `main`, `post`, `pre-if` and `post-if` are supported. One difference: on GitHub, `pre` scripts run at the start of the job, before any step. On Diffinery, an action's `pre` script runs immediately before its `main` script, as part of the same step. Post scripts run at the end of the job in reverse order, as on GitHub. ### Composite actions Composite actions (`runs.using: composite`) are supported, including `inputs`, `outputs`, `env`, `if`, `shell`, `working-directory` and nested `uses`. Composite actions nest at most 10 levels; deeper nesting fails with `Composite action nesting is too deep (max 10).` ### Docker container actions Actions with `runs.using: docker` are supported, with `runs.image` set to a `Dockerfile` in the action (built on the runner) or a `docker://` image, plus `args`, `entrypoint`, `env`, `pre-entrypoint` and `post-entrypoint`. A step can also run an image directly with `uses: docker://image`. Hosted runners have Docker; self-hosted runners need it installed. See [Docker container actions](https://diffinery.com/docs/actions/docker#docker-container-actions). ### Local actions `uses: ./path/to/action` reads the action from the workspace, so check out the repository first. Otherwise the step fails with `Can't find 'action.yml' or 'action.yaml' under ''. Did you forget to run actions/checkout before running your local action?` ### Actions stored on Diffinery `uses: acme/my-action@v1` always means the repository `acme/my-action` on GitHub, not on Diffinery. Actions in private GitHub repositories can't be used on hosted runners, because the download has no GitHub credentials. A [self-hosted runner](https://diffinery.com/docs/actions/runners#self-hosted-runners) can authenticate downloads with `DIFFINERY_GITHUB_TOKEN` in its environment. To use an action that lives in a Diffinery repository, check it out into a directory and use it as a local action: ```yaml - uses: actions/checkout@v4 with: repository: acme/my-action ref: v1 path: .actions/my-action token: ${{ secrets.ACTIONS_READ_TOKEN }} - uses: ./.actions/my-action ``` `ACTIONS_READ_TOKEN` is a personal or agent token with read access to `acme/my-action`, stored as a secret, because the job token can't read other private repositories. If `acme/my-action` is public, leave `token` out: the job token can read public repositories. ### Unsupported action runtimes Any other `runs.using` value fails the step with `Unsupported action runtime 'runs.using: ' in `. A version or repository that doesn't exist on GitHub fails with `Unable to resolve action '/@', repository or version not found`. A reference without `@ref` fails with `Expected format {owner}/{repo}[/path]@ref. Actual ''`. ### Actions that call the GitHub API Actions built on `@actions/github` or Octokit read `GITHUB_API_URL` and `GITHUB_SERVER_URL`, which point at Diffinery, and authenticate with the job token. Diffinery's REST API uses GitHub's paths, JSON shapes, `Link` header pagination and error format, so calls to endpoints Diffinery has work (see [REST API](https://diffinery.com/docs/reference/rest-api)), within the job's `permissions:` (see [GITHUB_TOKEN and permissions](#github_token-and-permissions)). Calls to the GraphQL API fail, because it doesn't accept a job's token yet. ### Actions that use the cache or artifact services Diffinery sets `ACTIONS_RUNTIME_TOKEN`, `ACTIONS_RESULTS_URL`, `ACTIONS_CACHE_URL`, `ACTIONS_RUNTIME_URL` and `ACTIONS_CACHE_SERVICE_V2` for JavaScript actions, Docker container actions and the built-ins (not for `run:` steps, as on GitHub). Actions that use the `@actions/cache` or `@actions/artifact` packages directly, and `docker/build-push-action` with `cache-from: type=gha` and `cache-to: type=gha`, store their caches and artifacts in Diffinery. See [The runtime services](https://diffinery.com/docs/actions/caching-and-artifacts#the-runtime-services). The official `actions/upload-artifact` and `actions/download-artifact` refuse to run on a server that looks like GitHub Enterprise Server, so the runner shows them `GITHUB_SERVER_URL=https://github.com`. Their API calls still go to Diffinery, and their `artifact-url` output is rewritten to point at Diffinery. ## Contexts and environment variables | Value | GitHub | Diffinery | | --- | --- | --- | | `github.server_url`, `GITHUB_SERVER_URL` | `https://github.com` | `https://diffinery.com` | | `github.api_url`, `GITHUB_API_URL` | `https://api.github.com` | `https://diffinery.com/api/v3` | | `github.run_id`, `GITHUB_RUN_ID` | A number, unique per run | A number: the run's number, the same as `github.run_number`. The API accepts it wherever it takes a run id. | | `github.repository_id` | A number | Diffinery's repository ID, a string | | `github.ref_protected` | `true` for protected branches | Always `false` | | `github.event.repository` | GitHub's repository object | The same object, with Diffinery's values; `id` is numeric and `private` and `visibility` reflect the repository | | `github.actor` for scheduled runs | The last person who edited the cron | `diffinery-scheduler` | | `github.token`, `secrets.GITHUB_TOKEN` | The job token | The job token, also available as `secrets.DIFFINERY_TOKEN` | | `github.actor_id`, `github.repository_owner_id`, `github.workflow_sha` | Set | Not set | | `runner.os`, `RUNNER_OS` | `Linux`, `Windows` or `macOS` | Always `Linux`, also on self-hosted macOS machines | | `runner.name`, `RUNNER_NAME` | The runner's name | `diffinery` | | `runner.environment`, `RUNNER_ENVIRONMENT` | `github-hosted` or `self-hosted` | `diffinery-hosted`, also on self-hosted runners | | `DIFFINERY` | Not set | `true` | `CI=true` and `GITHUB_ACTIONS=true` are set as on GitHub, so tools that detect GitHub Actions keep working. To run a step only on one forge, check the server URL: ```yaml - if: github.server_url == 'https://diffinery.com' run: echo "Running on Diffinery" ``` The complete list is in [Expressions and contexts](https://diffinery.com/docs/actions/expressions). ## GITHUB_TOKEN and permissions Every job gets a token, available as `secrets.GITHUB_TOKEN`, `secrets.DIFFINERY_TOKEN` and `github.token`. As on GitHub: - Its permissions come from the job's `permissions:`, else the workflow's, else the repository's default. `read-all`, `write-all`, `{}` and per-scope maps work as on GitHub, and a map sets every scope it doesn't list to `none`. - Each REST endpoint needs its scope (`contents`, `issues`, `pull-requests`, `statuses`, `checks`, `deployments`, `actions`, `packages` and so on). A request without it gets `403 Resource not accessible by integration (the workflow's GITHUB_TOKEN needs permissions: : )`. - It never administers the repository, never reads or changes secrets and variables, and never creates or changes workflow files. Branch protection applies to it. - It can open and approve pull requests only when the repository allows it, and its approvals don't count toward required reviews. - It can read any public repository on Diffinery, but no other private repository. - What it does starts no new runs, except `workflow_dispatch`. - It stops working when the job completes. Differences: - New repositories default to read-only tokens (`contents` and `packages` read), as GitHub does for new repositories. Repositories created before this setting existed default to read and write. An admin changes it on the repository's **Settings → Actions** tab or with `PUT /repos/{owner}/{repo}/actions/permissions/workflow`. - A run whose code came from an agent is held to the agent rules, so its token can't push or merge to the default branch or protected branches. [GITHUB_TOKEN permissions](https://diffinery.com/docs/actions/workflow-permissions) has the full model, the scope each endpoint needs, and how to change the default. ## Secrets, variables and environments | Feature | Status | | --- | --- | | Repository secrets and variables | Supported | | Organization secrets | Supported (CLI and API) | | Organization variables | Supported, through the REST API. Every repository in the organization sees them (no `private` or `selected` visibility). See [Organization variables](https://diffinery.com/docs/actions/secrets-and-variables#organization-variables). | | Environments with deployment branch policies (protected branches only, or branch and tag patterns) | Supported, through the REST API. See [Environments](https://diffinery.com/docs/actions/environments). | | Environment secrets and variables | Supported, through the REST API. They win over repository and organization values with the same name. Pull request runs never get environment secrets, and runs started by agents get them only from environments limited to protected branches. | | Team reviewers and custom deployment protection rules | Not supported. Required reviewers are people. | | Setting secrets with a sealed-box `encrypted_value` | Not supported yet. Send the plain `value` over HTTPS; it's encrypted at rest. | | Secrets in `pull_request` runs | Provided, because every pull request comes from a branch of the same repository | | Changing secrets and variables with an agent's token | Refused: only people manage secrets and variables | | Secret names starting with `GITHUB_` | Rejected for repository secrets, as on GitHub | See [Secrets and variables](https://diffinery.com/docs/actions/secrets-and-variables). ## Reusable workflows and OIDC Reusable workflows work as on GitHub, with these limits: they must live on the same Diffinery instance, calls nest at most 4 levels deep, one run calls at most 20, and a calling job can't have a matrix yet. See [Differences from GitHub](https://diffinery.com/docs/actions/reusable-workflows#differences-from-github) in Reusable workflows. OIDC works with `permissions: id-token: write`, and tokens are issued by `https://diffinery.com`. Configure your cloud provider to trust that issuer instead of `https://token.actions.githubusercontent.com`. The claims differ in a few places; see [Differences from GitHub](https://diffinery.com/docs/actions/oidc#differences-from-github) in OIDC. ## Porting checklist Work through this list for each workflow you move from GitHub. Most workflows need only the first two items. 1. Run `diffinery workflow validate` on each file and fix any errors. Read the warnings for ignored keys. 2. Push and watch the first run with `diffinery run watch` or on the **Actions** tab. 3. Replace `runs-on: windows-*` and `macos-*` with Linux, or with `[self-hosted, ...]` labels and a [self-hosted runner](https://diffinery.com/docs/actions/runners#self-hosted-runners). This includes `matrix.os` values used in `runs-on`. 4. Add `apt-get update` before `apt-get install`. 5. Install tools the hosted image doesn't have (Go, Java, Ruby, Rust, PowerShell, cloud CLIs) with a setup action or `apt-get`. 6. Check what each job does with `GITHUB_TOKEN`. In a new repository the default token only reads, so give jobs that push, tag, comment, label or merge the `permissions:` they need, or have an admin set the repository default to write (see [GITHUB_TOKEN permissions](https://diffinery.com/docs/actions/workflow-permissions)). Jobs that change workflow files, or that open or approve pull requests without the repository allowing it, need a personal or agent token from a secret. 7. Give `actions/checkout` of another private repository a token from a secret. 8. Recreate your environments, their branch policies, secrets and variables through the REST API (see [Environments](https://diffinery.com/docs/actions/environments)), and set required reviewers by Diffinery login (GitHub's numeric ids and teams don't carry over). 9. Replace `github.graphql` calls in `actions/github-script` with REST calls. 10. Replace `ghcr.io` with your instance's host (`diffinery.com` here) in image names and logins; see [Container registry](https://diffinery.com/docs/packages/container-registry#migrating-from-ghcrio). 11. Replace hard-coded `github.com` and `api.github.com` URLs with `${{ github.server_url }}` and `${{ github.api_url }}`. 12. Update OIDC trust policies in your cloud accounts to the Diffinery issuer and subject format. 13. Move actions from private GitHub repositories into a Diffinery repository and use them as local actions. [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github#workflows) covers moving the rest of the repository. ## Troubleshooting | Message | Cause and fix | | --- | --- | | `No Diffinery runner matches runs-on: . ...` | The labels aren't hosted Linux labels and don't include `self-hosted`. Use `ubuntu-latest`, or `[self-hosted, ...]` with a registered runner. For a matrix job, check the value `runs-on` got for that combination. | | `Error evaluating the job for this matrix combination: ` | An expression in `runs-on`, `name`, `timeout-minutes`, `continue-on-error` or `concurrency` failed for one matrix combination. | | `Resource not accessible by integration (the workflow's GITHUB_TOKEN needs permissions: ...)` | Add the scope to the job's `permissions:`. See [GITHUB_TOKEN permissions](https://diffinery.com/docs/actions/workflow-permissions). | | `refusing to allow a GitHub App to create or update workflow ...` | Job tokens never change workflow files. Use a personal or agent token from a secret. | | `GitHub Actions is not permitted to create pull requests. ...` | An admin allows it with `can_approve_pull_request_reviews`, and the job needs `pull-requests: write`. | | `Unable to resolve action '/@', repository or version not found` | The action or version doesn't exist on GitHub, or the repository is private. | | `Can't find 'action.yml' or 'action.yaml' under ''. ...` | Check out the repository before using a local action, and check the path. | | `Unsupported action runtime 'runs.using: ' in ` | The action uses a runtime other than `node*`, `composite` or `docker`. | | ``The `cmd` shell is not supported on Linux runners.`` | Use `bash` or `sh`. | | `Failed to fetch ref '' from /. Check that the ref exists and the token has read access.` | Checking out another private repository needs a token from a secret, the job lacks `contents: read`, or the ref doesn't exist. | | `No go-version specified and Go is not installed on this runner.` | Set `go-version` or `go-version-file`. | | `jobs.: a matrix on a job that calls a reusable workflow is not supported yet` | Move the matrix into the called workflow, or write one calling job per value. | | `A matrix may produce at most 256 jobs.` | Split the matrix. | | `A run may have at most 1000 jobs, ...` | Split the workflow, or trim its matrices. | | `Composite action nesting is too deep (max 10).` | Flatten nested composite actions. | | A built-in action behaves differently from the real one | Run the real action: set `DIFFINERY_BUILTINS: false` in the step's `env:`, or pin the action to a commit SHA. | | A job is skipped although its `if:` looks true | A job further up its `needs` chain failed, was cancelled or was skipped, and the `if:` doesn't call a status function. Use `if: always() && ...` or `if: ${{ !cancelled() && !failure() }}`. | --- # Connect AI apps > Add Diffinery to Claude, Claude Code, Codex or any MCP app with one URL and a browser sign-in. Pick your app and follow its guide. Source: https://diffinery.com/docs/connect Diffinery works with AI apps through its [MCP server](https://diffinery.com/docs/agents/mcp). Every app connects to the same address: ```text https://diffinery.com/mcp ``` On a [self-hosted Diffinery](https://diffinery.com/docs/self-hosting), use your instance's address instead, such as `https://git.example.com/mcp`. There is no token to copy. The app sends you to Diffinery in your browser, you choose whom it acts as and what it may do, and it's connected. You can see and disconnect every app under **Settings → Access tokens → Connected apps**, which also shows this URL with a copy button. ![Settings → Access tokens on Diffinery: the MCP server URL with a Copy button, links to the guides for Claude, Claude Code, Codex and other apps, and two connected apps, Claude Code and Codex, each acting as the agent ada-bot with write access.](https://diffinery.com/docs/images/connected-apps.webp) ## Pick your app | You use | What you do | Guide | | --- | --- | --- | | **Claude** on claude.ai, Claude Desktop or the Claude mobile apps | Add a custom connector with the URL, then approve it on Diffinery. | [Claude](https://diffinery.com/docs/connect/claude) | | **Claude Code** | Install the Diffinery plugin, then sign in from `/mcp`. | [Claude Code](https://diffinery.com/docs/connect/claude-code) | | **Live CI in Claude Code**, cloud sessions included | Install or upload the `diffinery-ci` plugin. | [CI status in Claude](https://diffinery.com/docs/connect/ci-status-in-claude) | | **Codex** (OpenAI's coding agent) | Install the Diffinery plugin, then run `codex mcp login diffinery`. | [Codex](https://diffinery.com/docs/connect/codex) | | **Cursor, VS Code or another MCP app** | Add the URL as a remote (HTTP) MCP server. | [Other apps](https://diffinery.com/docs/connect/other-apps) | | **Claude Code cloud environments** and other agent sandboxes | Paste three boxes from the repository's **Settings → Agent setup**. | [Cloud agent environments](https://diffinery.com/docs/connect/cloud-agents) | | **CI, scripts** (no browser) | Send an agent's token instead of signing in. | [Headless use](https://diffinery.com/docs/connect/how-sign-in-works#headless-use) | ## What a connected app can do Once connected, the app works with Diffinery the way you would, within the access you gave it: - Read code, branches and commits, compare branches, and commit files to a new branch without git. - Open pull requests with an [intent](https://diffinery.com/docs/collaboration/pull-requests), comment, review, merge, or turn on auto-merge. - Follow CI: list workflow runs, read the log of a failing job, and re-run or cancel runs. - File and update issues, and draft and publish releases. - Search and read these docs. The [MCP tool reference](https://diffinery.com/docs/reference/mcp-tools) lists every tool. In a terminal, Claude Code and Codex can also use git and the [`diffinery` CLI](https://diffinery.com/docs/reference/cli), which the Claude Code and Codex guides set up. ## You stay in control - **Act as an agent.** On the consent page you pick whether the app acts as you or as one of your [agents](https://diffinery.com/docs/agents/overview). An agent is the safer choice for an AI app: its commits and comments are marked as the agent's, it can't push to protected or default branches, and its pull requests need a person's approval unless a branch rule says otherwise. - **Choose the access.** Read, Write or Admin. Write is enough for pull requests, reviews and issues. Admin is never preselected. - **Disconnect any time.** **Settings → Access tokens → Connected apps** lists every app with whom it acts as, its access and when it was last used. **Disconnect** ends it at once. How the sign-in works, and what each part of the consent page means, is in [How sign-in works](https://diffinery.com/docs/connect/how-sign-in-works). ## For AI agents reading this page If you are an agent setting yourself up: - Running in a terminal with a person nearby: ask them to install the plugin for your app ([Claude Code](https://diffinery.com/docs/connect/claude-code), [Codex](https://diffinery.com/docs/connect/codex)) and approve the sign-in. Don't try to complete a browser sign-in yourself. - Running in a cloud sandbox for one repository: `diffinery setup --repo /` sets up git and gh and checks them; the person sets up the sandbox from the repository's **Settings → Agent setup** ([Cloud agent environments](https://diffinery.com/docs/connect/cloud-agents)). - Running headless with `DIFFINERY_TOKEN` set: add the server with an `Authorization: Bearer ${DIFFINERY_TOKEN}` header, as in [Headless use](https://diffinery.com/docs/connect/how-sign-in-works#headless-use). `diffinery mcp-config` prints the snippet. - Either way, `diffinery auth setup-git` lets git push with the same sign-in, and `diffinery auth setup-gh` makes `gh` work against diffinery.com ([GitHub CLI](https://diffinery.com/docs/agents/github-cli)).