| .github | ||
| apps | ||
| containers | ||
| packages | ||
| scripts | ||
| .gitignore | 97 B | |
| package.json | 430 B | |
| pnpm-lock.yaml | 87.8 KB | |
| pnpm-workspace.yaml | 53 B | |
| README.md | 7.7 KB | |
| tsconfig.base.json | 391 B | |
| turbo.json | 221 B |
Diffinery
A git forge for teams of people and AI agents, running entirely on Cloudflare. Git hosting, pull requests and reviews, issues, GitHub-Actions-compatible CI, an MCP server for agents, and sandboxes, with no servers to run.
- Drop-in for GitHub workflows.
.github/workflows/*.ymlruns as-is: same triggers, expressions, matrices,needs, outputs, caches, artifacts, secrets, OIDC,actions/checkout,setup-node/python/go, and remote JavaScript and composite actions. - Built for agents. Agents are first-class accounts owned by a person or
team, with their own tokens and limits. They can't push or merge to protected
branches, and their pull requests always need a human approval. Every commit
they make is stamped with who they act for. They work through MCP
(
/mcp) or the REST API, and can start sandboxes to build and test. - Secure by default. Cloudflare Access handles sign-in, while invites, roles and branch protection decide what people can do. Pushes are scanned for leaked credentials. Secrets use envelope encryption, and every sensitive action goes to an append-only audit log.
How it fits on Cloudflare
| Piece | Cloudflare product |
|---|---|
| HTTP, git smart HTTP, REST API, MCP, web UI | Workers (Hono) |
| One repository: refs, objects, PRs, issues, reviews, checks, runs | Durable Object with SQLite (RepoDO), one per repository |
| Large objects, Git LFS, logs, caches, artifacts, event archive | R2 |
| Accounts, orgs, tokens, invites, notifications, audit log | D1 |
| Webhooks, notifications, audit fan-out | Queues (with a dead-letter queue) |
| Workflow runs (durable, survive restarts, 6 h job timeout) | Workflows |
| Job runners and agent sandboxes | Containers (Ubuntu 24.04 image in containers/runner) |
Scheduled workflows (on: schedule) | Cron Triggers |
| Live run logs and PR updates | Durable Object WebSockets (hibernation) |
| Sign-in | Cloudflare Access (GitHub, Google, email one-time PIN, etc.) |
apps/diffinery the Worker (src/index.ts), D1 migrations, wrangler config, e2e test
apps/cli the `diffinery` command-line client
containers/runner runner agent + sandbox server, and the container image
packages/git-core git objects, packfiles, deltas, diff/merge (pure TypeScript)
packages/workflow-yaml GitHub Actions workflow parser, expressions, matrix, cron
packages/shared types shared by the Worker and the runner
scripts bootstrap.sh, ensure-secrets.sh, render-config.mjs
Deploying
Deploys run from GitHub Actions on every push to main (.github/workflows/deploy.yml).
The workflow needs two repository secrets:
CLOUDFLARE_API_TOKEN: account permissions Workers Scripts, D1, R2, Queues, Workflows, Containers and Access: Apps and Policies (all Edit), and zone permission Workers Routes Edit ondiffinery.com.CLOUDFLARE_ACCOUNT_ID
On each deploy, scripts/bootstrap.sh creates anything that is missing: the D1
database, R2 bucket, queues and the two Access applications (sign-in for the
site, and a bypass for the git, API, MCP and runner paths, which check
Diffinery tokens themselves). It then applies D1 migrations. wrangler deploy
builds and pushes the runner image. On the first deploy, ensure-secrets.sh
generates MASTER_KEY and the OIDC signing key inside the job, so neither
value is ever printed.
If the token can't read your Zero Trust organization, set a repository
variable ACCESS_TEAM_DOMAIN (for example codician.cloudflareaccess.com).
To let people sign in with GitHub, add GitHub as a login method under Zero Trust → Settings → Authentication. Email one-time PIN works without any setup.
Inviting people
- The emails in
BOOTSTRAP_ADMINS(inapps/diffinery/wrangler.jsonc) become site admins the first time they sign in. - Anyone else who signs in lands on a waiting page. They can request access,
which admins approve, or an admin or org owner can send an invite from
Settings → People or with
diffinery invite friend@example.com --org codician. - Repository and org roles (read, triage, write, maintain, admin) decide what each person can do.
Nobody needs a Cloudflare account. They need an Access login and, for git and the CLI, a personal token from Settings → Tokens.
git clone https://diffinery.com/codician/website.git # username: anything, password: your dfy_ token
diffinery login && diffinery auth setup-git # or let the CLI handle credentials
Agents
Create an agent under Settings → Agents or with diffinery agent create reviewer-bot --org codician.
Then point any MCP client at it:
{ "mcpServers": { "diffinery": { "type": "http", "url": "https://diffinery.com/mcp", "headers": { "Authorization": "Bearer dfy_…" } } } }
Tools include get_file, list_tree, commit_files (no git client needed),
create_branch, create_pull_request (with an intent for reviewers),
review_pull_request, merge_pull_request (policy-guarded), issues,
list_workflow_runs and get_job_logs, rerun_workflow, and
sandbox_create/sandbox_exec for running builds and tests.
Agent guardrails apply everywhere: git, REST, MCP and the web UI.
- An agent's role is capped at write, and never exceeds its owner's role.
- Agents can't push to the default branch or protected branches, and can't
merge there. Turn this on per branch with
agentsMayPushoragentsMayMerge. - A pull request opened by an agent needs at least one human approval, and approvals from agents don't count toward it.
- Agents can't change branch protection or read or set secrets.
Workflows
Put workflow files in .github/workflows/ (or .diffinery/workflows/).
Supported triggers are push, pull_request, workflow_dispatch (with
inputs) and schedule, with branch, tag and path filters. Supported workflow
features:
needsand job outputs,ifwithsuccess(),failure(),always()andcancelled(),strategy.matrixwith include and exclude,fail-fastandmax-parallel,concurrencywithcancel-in-progress, andtimeout-minutes.continue-on-error,defaults.run,envat every level,$GITHUB_OUTPUT,$GITHUB_ENV,$GITHUB_PATH,$GITHUB_STEP_SUMMARY, and masking of secrets and::add-mask::values.secrets.*,vars.*,GITHUB_TOKEN(a per-job token), andpermissions: id-token: writefor OIDC (issuerhttps://diffinery.com).runs-on: ubuntu-latest(and anyubuntu-*orlinuxlabel) runs in a Cloudflare Container.runs-on: [self-hosted, …]jobs wait for a runner you start withdiffinery runner -R owner/repo --labels gpu,macos. Use that for macOS, GPUs or private networks.
Not supported yet: reusable workflows (jobs.<id>.uses), job
container: and services:, Docker container actions, actions/github-script,
Windows and macOS hosted runners, pull_request_target, merge_group, and
deepen-not / partial clone filters. Pull request runs use the head commit
rather than a test merge commit. A job that uses an unsupported feature fails
with a clear message instead of misbehaving.
Developing
pnpm install
pnpm -r build && pnpm -r typecheck && pnpm -r test
pnpm --filter @diffinery/app db:migrate:local
pnpm dev # http://localhost:8787, signed in as dev@diffinery.local
pnpm --filter @diffinery/app e2e # wrangler dev + real git + the runner agent
The end-to-end test does the following:
- Pushes a repository with real
git. - Runs its CI through the actual runner agent.
- Checks secret scanning and branch protection.
- Has an agent open a pull request that needs a human approval and a green check, then merges it.
- Clones shallow, then deepens the clone.
- Drives the MCP server.