# 4. Copies versus references

Source: https://archil.com/guides/storage-for-agents/copies-and-references · Part of The buyer’s guide to storage for AI agents · Facts checked 2026-11-04

**The short answer:** Forking an attempt, handing a workspace to another machine, and leaving a vendor each cost either a copy of the data or a new pointer to it. A copy takes time and storage in proportion to the workspace, and a pointer doesn’t. On Archil-managed disks the first two are pointers, but leaving is a copy, because those disks use our internal format.

Teams that moved large files between services learned, years ago, to pass pointers instead of data. A service uploaded a 1 GB file to S3 once and put the URL in a queue message. Every service after it received the URL, not the gigabyte.

An agent’s unit of work isn’t one file. It’s a workspace: a repository, its installed packages, a SQLite database, and the notes the agent left for its next run. Three moments in a workspace’s life ask you to move it:

- an attempt needs a fork of its own to work in;
- another machine needs to pick up the work;
- you leave the vendor that stores it.

Each moment costs one of two things. A copy reads and writes every byte, so its time and storage grow with the workspace. A reference gives the new owner a pointer to data that already exists, so it costs about the same at 1 GiB as at 1 TiB. This chapter prices all three moments with one workspace, and shows why no storage format we know of makes all three references, ours included.

## Forking an attempt

Take a 100 GiB workspace and a harness that wants five attempts at a failing test. If a fork is a copy, each attempt waits while 107 GB is read and written again. At 500 MB/s, a brisk rate that we assume here rather than one we measured, that’s about 215 seconds per attempt. Five attempts in a row spend 18 minutes copying and store 600 GiB, almost all of it identical.

On an Archil-managed disk, a checkpoint takes 13 ms and a branch 33 ms at the median, and neither depends on the size of the disk. (The p95s are 19 ms and 36 ms, measured with our CLI from a c7gn.2xlarge in AWS `us-east-1`. The branch time includes opening a new TLS connection. For the method, see [Limits](https://docs.archil.com/reference/limits) and the [latency benchmark](https://docs.archil.com/reference/benchmarks/latency) in our docs.)

**Copy or branch**

A full copy and a branch of a 100 GiB workspace start at the same moment, played in real time. After 5 seconds, the copy, at an assumed 500 MB/s, has written 2,500 MB of about 107,000 MB and has about 3.5 minutes to go. The branch was ready in 33 ms, and the agent has been working in it ever since.

A branch is fast because it’s a reference. A file system already keeps a map from each file to the blocks that hold its data. A copy-on-write branch starts a second map that points at the same blocks, so no data moves when it’s made. When the attempt rewrites a block, the storage puts the new data in a new block and repoints only the branch’s map.

**Shared blocks, then one new one**

A disk’s map points at four blocks, `A` to `D`. A checkpoint freezes the map. A branch starts with its own map pointing at the same four blocks, so no data moves. When the branch rewrites `C`, the storage writes a new block, `C′`, and repoints only the branch. The parent still reads `C`, and the two keep sharing `A`, `B`, and `D`.

The reference changes what a fork costs, not only how long it takes. A branch stores what its attempt changed, so five attempts that each rewrite 2 GiB store about 110 GiB in all, not 600 GiB. A harness that pays that little forks more often. It can checkpoint after every turn that succeeds, and branch back to the last good checkpoint when a turn fails. For how snapshots and writable clones work block by block, and why they survive a power cut, see the field guide’s chapter on [copy-on-write](https://archil.com/guides/how-file-systems-work/copy-on-write).

## A fork of a copy that lags

A reference is only as current as the data it points at. Some storage acknowledges `fsync()` once a write reaches the sandbox’s local drive, and uploads it to durable storage later. Its forks are made from the durable copy, which trails what the program was told is safe. [The obvious ways to build it](https://archil.com/guides/storage-for-agents/the-obvious-ways-to-build-it#an-upload-when-the-agent-stops) covers that design. Here, the question is only what a fork is made from.

We tested this on Vercel Drives. A sandbox wrote a 4 KiB file and a 64 MiB file, called `fsync()`, and the script then forked the Drive and read the fork from a new sandbox. Every fork requested in the first second after `fsync()` returned lacked the new file: 29 of 29. At 5 s and again at 30 s, 9 of 10 forks still lacked it. From 60 s on, every fork had it. (The script and every result are in [Vercel Drive fsync durability](https://docs.archil.com/reference/benchmarks/vercel-drive-durability) in our docs. The test ran in Vercel’s `pdx1` region, with 8 to 11 trials per delay.)

Vercel’s docs describe a Drive fork two ways: as “copying the drive’s data”, and as a drive that inherits its parent’s data “but stores its own changes independently”. (Both phrases are from Vercel’s [Drives](https://vercel.com/docs/sandbox/concepts/drives#forking-a-drive) documentation.) We didn’t time Drive forks, so we can’t say which one you pay for. Either way, the fork came from the copy that lagged.

**What the fork is made from**

Two forks requested right after `fsync()` returns. On storage that acknowledges `fsync()` from the sandbox’s local drive, the write reaches the store that forks are made from later, in the background, so the fork lacks the file. In our test of Vercel Drives, every fork requested in the first second lacked it, 29 of 29, and forks were intact only from 60 s on. On Archil, `fsync()` returns after the write is replicated across availability zones, and the checkpoint and branch point at that replicated state, so the branch has the file.

Our branches don’t have that gap, because a checkpoint is taken from the same replicated state that `fsync()` waits for. From inside a Vercel sandbox, checkpointing a disk, branching it, and mounting the branch took about 0.9 s end to end. A 1 GiB file was intact in the branch. Call `fsync()` on the files a turn wrote before you checkpoint it.

## Handing the workspace to another machine

The machine that finishes a task often isn’t the one that started it. Moving the workspace between them is the second moment.

The copy version is the sync-to-S3 design from [the obvious ways to build it](https://archil.com/guides/storage-for-agents/the-obvious-ways-to-build-it). Machine A packs the workspace and uploads it, and machine B downloads and unpacks it. For the 100 GiB workspace at the assumed rate, that’s about 215 seconds up and 215 down, around 7 minutes before B runs a command. B also gets the workspace as it was when the upload started, so anything A wrote afterward stays behind.

The reference version hands over the disk itself. A runs `archil unmount`, which flushes what A has written, and B mounts the same disk in 50 ms at the median. Nothing is copied up front. B fetches each block the first time it reads it: about 0.5 ms for 4 KiB served from our servers’ cache, or 10 to 30 ms when the block has to come from S3. (Both read times are from our [performance](https://docs.archil.com/details/performance) page; the first is the median for a 4 KiB read that misses the client’s cache.) A machine that reads 2 GiB of a 100 GiB workspace moves about 2 GiB.

**Two ways to hand off a workspace**

Two ways to hand a workspace from machine A to machine B. Copying it across uploads the whole workspace to a bucket and downloads it again before B can start: for 100 GiB at an assumed 500 MB/s, about 7 minutes. A file A wrote after the upload began never reaches B. Mounting the same disk takes one unmount on A and one mount on B, 50 ms at the median, and B then fetches only the files it opens.

In the default exclusive mode, one machine writes to a disk at a time, so B mounts it for writing once A has let go. Shared mode lets machines check out separate paths of one disk. [Where the truth lives](https://archil.com/guides/storage-for-agents/where-the-truth-lives) covers how that right to write moves between machines.

A reference hand-off isn’t unique to us. An EBS volume can be detached from one instance and attached to another, as long as both are in the same availability zone. (From AWS’s guide to [attaching a volume](https://docs.aws.amazon.com/ebs/latest/userguide/ebs-attaching-volume.html): “You can attach volumes to instances that are in the same Availability Zone only.”) A Vercel Drive mounts read-write in one sandbox at a time. In our test, a Drive handed over by stopping the writing sandbox had the file intact in 10 of 10 trials. What differs is how far the pointer reaches: one zone, one vendor’s sandboxes, or any Linux machine that runs our client.

## What a branch shares

A branch shares blocks with its parent, and it shares the parent’s access rules too. Three things follow for Archil’s branches today:

- **Space comes back only from what a branch owns.** An attempt that rewrites its whole workspace stores as much as a copy. Deleting a branch would free only the blocks that no other branch or checkpoint still reads.
- **You can’t delete an individual branch or checkpoint.** The data an abandoned attempt wrote stays on the disk. If you fork thousands of times a day, plan for that.
- **A branch isn’t a security boundary.** Credentials cover the whole disk, every branch and checkpoint included. Give each untrusted tenant its own disk, and keep branches for attempts that may see each other’s files.

**What forks use**

An interactive space meter for one 100 GiB checkpoint and several writable forks of it. Every fork references 100 GiB. The disk stores the checkpoint once plus what each fork rewrote: four forks that have each rewritten 10% store 140 GiB, against the 500 GiB the five trees show. Each fork uses 10 GiB, which deleting it would free. If the forks rewrote different blocks, every block of the checkpoint is still read by some fork, so the checkpoint uses nothing and deleting it frees nothing. If they all rewrote the same blocks, only the checkpoint still reads the old versions, and deleting it frees 10 GiB. A fork that has rewritten 100% of the disk costs as much as a full copy.

## Leaving a vendor

The third moment happens once, if at all, and it’s the one buyers check least. Whether leaving is a copy or a reference depends on the format your files are in on the day you go.

If they’re ordinary objects at their paths, in a bucket you own, leaving is a reference. You stop writing, let the last sync land, and point the next system at the bucket. Anything else is a copy: you read every byte back through the product that wrote it, and write it somewhere new.

Leaving an Archil-managed disk, the default, is a copy. It’s stored in our internal format, in a bucket we operate. You export it through the disk’s own S3 API, or mount it and copy it with `rsync -aH` to keep owners and links. Exporting 500 GB costs $35 in transfer, and takes about 17 minutes at the assumed rate.

A disk synced to your own bucket in S3, GCS, R2, or another S3-compatible store is a reference. Each file is already an object at its path, and deleting the disk leaves the objects where they are. The bucket doesn’t hold the whole file system, though. Mode bits, owners, and extended attributes stay in Archil. A symbolic link arrives as a text file holding its target, and a hard link as a full copy.

**What your bucket sees**

The figure lists one agent workspace (a Git repository, a shell script with mode 755, a symbolic link, an installed package, a Parquet file, and a SQLite database) as each kind of storage leaves it in object storage.

An Archil-managed disk, the default, leaves nothing in your bucket: it’s stored in Archil’s internal format, in a bucket Archil operates, and you list it through the disk’s own S3 API, where the symbolic link isn’t readable. A bucket-synced Archil disk leaves every file as an ordinary object at its path; the script’s mode stays in Archil, and the symbolic link becomes a text file holding its target. Mountpoint for Amazon S3 leaves ordinary objects too, but can’t write the Git repository, the symbolic link, or the SQLite database, and can’t change modes. Amazon S3 Files leaves ordinary objects as new versions, keeps the mode as object metadata, and stores the link as an object whose encoding AWS doesn’t document. JuiceFS leaves numbered block objects under `chunks/`, with names and modes in its metadata engine. A block volume leaves a snapshot you can’t read as files, and a sandbox vendor’s disk leaves nothing in your bucket at all.

For how each of these designs maps files onto objects, see the field guide’s chapter on [a file system on an object store](https://archil.com/guides/how-file-systems-work/a-file-system-on-an-object-store).

## The map behind every cheap fork

A reference needs something to point through. A copy-on-write branch is a second map over shared blocks, so the storage has to keep that map, and it has to name blocks by something other than their paths. A bucket of ordinary objects has no such map: each object’s key is its path. Two trees that share most of their files can’t both live at the same keys. A fork there is either a copy under a new prefix, or a map kept somewhere else, which is a format of its own.

The products in this guide that fork without copying each keep that map, and the map is what an exit has to carry out. JuiceFS clones a directory by copying only its metadata, which lives in an engine you run, and its bucket holds numbered blocks you can’t read as files. AWS keeps EBS snapshots incrementally, in S3 buckets you can’t access directly.

We’re no exception. Checkpoints and branches work on Archil-managed disks only, and those disks use our internal format. A bucket-synced disk keeps your files at their paths, and it can’t checkpoint or branch. So you choose per disk. A managed disk suits agents that fork often. A bucket-synced disk suits files that other tools must read where they land, or a workspace whose exit matters more than its forks. Moving from one kind to the other is a copy: create the new disk and copy the data into it.

**Copy or pointer, three times**

An interactive ledger for one workspace and three moments: forking an attempt, handing the workspace to another machine, and leaving. Copy times use an assumed 500 MB/s, and pointer times are our measured medians. For a 100 GiB workspace on a disk that lives on one machine, all three are copies: about 3.6 minutes to fork, about 7 minutes to hand off by upload and download, and about 3.6 minutes to export. On an Archil-managed disk, a fork is a pointer (a 13 ms checkpoint and a 33 ms branch), a hand-off is a pointer (a 50 ms mount, after which only the files read move), and leaving is a copy of the whole workspace, $7.52 in transfer for 100 GiB. On a bucket-synced Archil disk, a fork is a copy, because checkpoints and branches need a managed disk. A hand-off is a pointer, and so is leaving: nothing moves, although modes and links stay behind.

To find out which kind of fork a vendor sells, time a fork of a small disk and of your largest one. A fork whose time grows with the disk is a copy, whatever it’s called. Then fork the moment `fsync()` returns and compare checksums, and ask in writing what format your files will be in on the day you leave. [Can you fork it?](https://archil.com/guides/evaluating-storage/can-you-fork-it) and [Where does your data live?](https://archil.com/guides/evaluating-storage/where-does-your-data-live) have the scripts for both tests.

Between those three moments, the workspace mostly sits idle. [What you pay for](https://archil.com/guides/storage-for-agents/what-you-pay-for) covers what the idle time costs.
