Skip to content
FLAVIO COPES
flaviocopes.com
2026

Cloudflare Artifacts: Git storage built for AI agents

By Flavio Copes

Learn how Cloudflare Artifacts gives AI agents isolated Git repositories, short-lived access tokens, forks, and a programmable Workers API.

~~~

AI coding agents create a lot of files.

They edit code, generate configuration, run experiments, and produce results. We need a place where all this work can live.

A temporary folder works until the process disappears. Object storage keeps files, but it does not give us commits, branches, or diffs. GitHub gives us Git, but creating thousands of small repositories for short-lived agents is not its main job.

Cloudflare Artifacts is built for this problem.

It gives every agent a real Git repository, with standard clone, pull, and push commands. But those repositories are also programmable from a Cloudflare Worker or the REST API.

Artifacts is currently in beta. You need access enabled on your Cloudflare account before following this tutorial.

People are already using it at scale. Dillon Mulroy from Cloudflare says Artifacts is nearing 50,000 new repositories per day.

That’s the interesting shift. A repository is no longer something a team creates occasionally. An application can create one for every agent, task, or experiment, then keep or delete it when the work is done.

What is Cloudflare Artifacts?

Artifacts is versioned, Git-compatible storage.

Each repository has:

Repositories live inside namespaces. A namespace is a container you can use for an environment, a customer, or a group of agents.

For example:

agents/
  agent-001
  agent-002
  agent-003

You don’t create the agents namespace separately. Artifacts creates it when you add the first repository.

Create your first repository

The simplest way to start is through Wrangler.

First, log in:

npx wrangler login

Now create a repository called agent-001 inside the agents namespace:

npx wrangler artifacts repos create agent-001 \
  --namespace agents \
  --default-branch main

You can inspect it with:

npx wrangler artifacts repos get agent-001 \
  --namespace agents

Wrangler prints the repository details, including its Git remote.

It looks like this:

https://<ACCOUNT_ID>.artifacts.cloudflare.net/git/agents/agent-001.git

Create a write token

Every repository has its own tokens. A read token can clone, fetch, and pull. A write token can also push.

Let’s create a write token that expires after one hour:

npx wrangler artifacts repos issue-token agent-001 \
  --namespace agents \
  --scope write \
  --ttl 3600

Copy the remote and token into two shell variables:

export ARTIFACTS_REMOTE='https://<ACCOUNT_ID>.artifacts.cloudflare.net/git/agents/agent-001.git'
export ARTIFACTS_TOKEN='art_v1_<TOKEN>?expires=<TIMESTAMP>'

Treat the token like a password. Do not commit it or print it in logs.

Push a commit

Now let’s create a small local repository:

mkdir agent-work
cd agent-work

git init -b main
printf '# Work produced by agent-001\n' > README.md

git add README.md
git commit -m "Add initial result"
git remote add origin "$ARTIFACTS_REMOTE"

Push the commit using the token:

git -c http.extraHeader="Authorization: Bearer $ARTIFACTS_TOKEN" \
  push -u origin main

This is a normal Git push. Artifacts speaks the Git smart HTTP protocol, so your existing Git client works without a plugin.

Notice that we did not put the token in the remote URL. The http.extraHeader option sends it only for this command.

You can clone the repository in the same way:

git -c http.extraHeader="Authorization: Bearer $ARTIFACTS_TOKEN" \
  clone "$ARTIFACTS_REMOTE" agent-work-copy

Create repositories from a Worker

The CLI is useful for us. The Workers binding is useful when your application needs to create repositories automatically.

Create a Worker:

npm create cloudflare@latest artifacts-worker
cd artifacts-worker

Choose a Worker-only TypeScript project.

Add the Artifacts binding to wrangler.jsonc:

{
  "$schema": "./node_modules/wrangler/config-schema.json",
  "name": "artifacts-worker",
  "main": "src/index.ts",
  "compatibility_date": "2026-07-10",
  "artifacts": [
    {
      "binding": "ARTIFACTS",
      "namespace": "agents"
    }
  ]
}

Generate the binding types:

npx wrangler types

Now replace src/index.ts with this:

interface Env {
  ARTIFACTS: Artifacts
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url)

    if (request.method !== 'POST' || url.pathname !== '/repos') {
      return new Response('Use POST /repos', { status: 404 })
    }

    const created = await env.ARTIFACTS.create('agent-002', {
      description: 'Workspace for agent-002',
      setDefaultBranch: 'main',
    })

    return Response.json({
      name: created.name,
      remote: created.remote,
      token: created.token,
    })
  },
} satisfies ExportedHandler<Env>

Start the Worker:

npx wrangler dev

Then create the repository from another terminal:

curl -X POST http://localhost:8787/repos

The response contains the repository name, remote URL, and initial write token:

{
  "name": "agent-002",
  "remote": "https://<ACCOUNT_ID>.artifacts.cloudflare.net/git/agents/agent-002.git",
  "token": "art_v1_<TOKEN>?expires=<TIMESTAMP>"
}

The example returns a write token to keep the flow visible. Do not expose this endpoint publicly without authentication.

In production, verify the caller first. Create short-lived read tokens for clone operations, and only create write tokens when a client must push.

Give every agent its own fork

One useful pattern is to keep a baseline repository, then fork it for every task.

The agent starts with the same files, but works in isolation:

const baseline = await env.ARTIFACTS.get('project-baseline')

const fork = await baseline.fork('agent-003', {
  description: 'Isolated workspace for agent-003',
  defaultBranchOnly: true,
})

console.log(fork.remote)

The fork gets its own history, tokens, and lifecycle. Changes made by agent-003 do not affect the baseline.

When the work is done, your application can inspect the commits or diff the result. It can keep the repository as an audit trail, or delete it.

Import an existing GitHub repository

You can also import a public Git repository:

const imported = await env.ARTIFACTS.import({
  source: {
    url: 'https://github.com/cloudflare/workers-sdk',
    branch: 'main',
    depth: 1,
  },
  target: {
    name: 'workers-sdk-copy',
  },
})

console.log(imported.remote)

A shallow import is useful when an agent needs the current code, but not the entire history.

Where Artifacts fits

Artifacts is not a GitHub replacement.

GitHub is where people collaborate through issues, pull requests, reviews, and releases. Artifacts is a programmable Git storage layer for applications, automations, and agents.

It is a good fit when you need:

If you only need to store files, R2 is simpler. Use Artifacts when commits, branches, diffs, and rollback are part of the data model.

Current limits

At the time of writing, each repository can store up to 10 GB. An account gets 1 TB total by default, and Cloudflare says this can be raised on request.

The number of repositories and namespaces is unlimited. Both control-plane and per-repository Git operations allow 2,000 requests per 10 seconds.

Check the current limits before designing around those numbers. Artifacts is still in beta, so they can change.

The interesting part

Agents already know Git.

They know how to clone a repository, create a branch, commit files, inspect a diff, and push the result. Artifacts doesn’t invent a new filesystem API for that workflow.

It gives agents the interface they already understand, while giving us an API to create and control repositories at scale.

That’s the part I find interesting. The storage is useful, but the real idea is simpler: give every agent an isolated place to work, and make the handoff a Git remote.

~~~

Related posts about cloudflare: