Diffinery

codician/diffinerypublic

Open-source, agent-first GitHub and GitHub Actions alternative that runs on your own Cloudflare account: git hosting, pull requests, code review and drop-in GitHub Actions YAML on Workers, Durable Objects, R2 and Containers.

268 lines · 14.5 KBRaw History

title: Quickstart description: Go from an invite to a working Diffinery repository: passkey, token, CLI, first push, workflow run, pull request, release and an AI agent over MCP.

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. Replace them with your own names.

What you need

  • A browser that supports passkeys (current Chrome, Safari, Edge or Firefox).
  • Git 2.26 or newer (git --version).
  • Node.js 22 or later, for the diffinery CLI (node --version).
  • An invite to Diffinery. Diffinery is invite-only: a site administrator, an organization owner or admin, or a repository admin sends it.

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/<username>/....
  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.

2. Create a token

Git, the CLI, the REST API and MCP clients authenticate with a personal access token, not a passkey.

  1. Go to Settings → Access tokens (https://diffinery.com/settings/tokens).

  2. Under Create a token, enter a Name (for example laptop), keep Expires in (days) at 90 (1 to 366), and pick a Scope:

    ScopeAllows
    ReadClone, 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).
    AdminEverything you can do, including repository settings and secrets, and creating organizations, agents, invitations and other tokens.

    For this guide, keep Write. Leave Restrict to repositories empty.

  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. See Personal access tokens.

3. Install the CLI and log in

Install the diffinery command-line client (needs Node.js 22 or later; make sure ~/.local/bin exists and is on your PATH):

curl -fsSL https://diffinery.com/-/cli/diffinery.mjs -o ~/.local/bin/diffinery && chmod +x ~/.local/bin/diffinery

Log in with the token and let Git use it too:

diffinery login            # paste the dfy_ token when asked
diffinery whoami           # prints diffy
diffinery auth setup-git   # git clone/fetch/push to diffinery.com now use the token

diffinery login saves the server URL and token to ~/.config/diffinery/config.json (readable only by you). The DIFFINERY_TOKEN and DIFFINERY_URL environment variables override it, which is handy in CI. See CLI reference.

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.

diffinery repo create website --org acme --private -d "Marketing site"

REST API.

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.

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.

From an existing project:

cd website
git remote add origin https://diffinery.com/acme/website.git
git push -u origin main

Or start from scratch:

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 and Git over HTTPS.

6. Add a workflow and watch it run

Diffinery runs GitHub Actions workflows from .github/workflows/. Add one:

# .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
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):

    diffinery run list             # newest runs first, with their ID
    diffinery run watch <run-id>   # follow it until it finishes; exits non-zero if it fails
    diffinery run logs <job-id>    # 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. 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.

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:

permissions:
  contents: write
  pull-requests: write

A repository admin can also change the default. See Workflow permissions.

7. Open a pull request

Make a change on a branch and push it:

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.

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:

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 and Branch protection.

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):

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.

To deploy from a workflow with its own secrets and branch rules, use an environment (environment: production on a job); see 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.

Creating an agent also creates its first token, and tokens can't create tokens, so create agents in the web UI under Settings → Agents. It shows the agent's token once (scope write, valid for 90 days). 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:

{
  "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 and the MCP tool reference.

Next steps