Blog

Why we stopped using JuiceFS for AI agent storage

· by

TL;DR. Our AI agents did not need a live filesystem shared over the network. They needed their own copy of the files and saved versions of that copy. On September 30, 2026, we decided to replace JuiceFS. The only reason we wrote down was that we did not want to keep maintaining it.

Before: every file operation went through FUSE to a network filesystem with replicated metadata.

After: the agent uses a local disk. The platform saves a version every minute during a run and at the end.

Each plori user gets a cloud AI agent whose files persist between sessions. In September 2026 we changed how we stored those files three times and planned a fourth change. Each change solved a specific problem but kept one assumption: an agent needs a live, mounted, network filesystem.

What did agent storage at plori look like with JuiceFS?

JuiceFS keeps file contents in object storage and metadata, such as file names and sizes, in a database. Programs use it through FUSE, a Linux feature that lets an ordinary program act as a filesystem.

By June 2026, every agent had its own folder on one shared JuiceFS filesystem. Agents run code we did not write. So a trusted gateway we built, called orlop, held the only mount and kept each agent in its folder. An earlier post explains why.

Why did we give each agent its own JuiceFS volume?

In early September, each agent got its own JuiceFS volume. Its metadata was a SQLite file, a database stored in one local file. Litestream copied the changes in that file to object storage.

In July we rejected one filesystem per agent, partly because each one needed its own metadata database. With SQLite, the metadata was a local file instead, so we tried the idea again. It was also a prerequisite for making our servers replaceable. With this change, we retired orlop on September 6.

Litestream then needed patches. On September 8, before our fix, a restore in our test recovered only 80 of 201 saved rows.

Why did we mount JuiceFS inside the agent's sandbox?

Each agent ran in a gVisor sandbox, which handles system calls in its own kernel that runs as a normal program. At first, the host mounted the volume before the sandbox started. A new session waited a median of 4.6 s for its disk on staging and 8.0 s in production. A test that mounted the volume from inside a running sandbox took 0.3 s. So in mid-September we moved the mount inside the sandbox.

FUSE inside gVisor had gaps that broke git. We patched our own fork of gVisor. Running a FUSE filesystem inside gVisor covers the details.

Small files were slow on FUSE even without gVisor. A git checkout of 9,749 files shows the difference. All cases ran on the same node with the same image, each FUSE case three times and the local case once.

Where the checkout wrote Time
Local directory, host kernel 0.78 s
JuiceFS FUSE mount, host kernel, no gVisor 39.7 to 43.5 s
JuiceFS FUSE mount, under gVisor 83.8 to 90.1 s

The JuiceFS mount was about 50 times slower than a local directory, and gVisor doubled that.

On September 18, a long write stalled our own mount supervisor's health signal, and the platform marked three sandboxes dead and cancelled the run.

Why did sharing files between agents need a gateway again?

In parallel, we wanted a manager agent and its workers on one project folder, each with its own copy. But only one process could safely own the SQLite metadata file.

So our design from September 13 put one trusted gateway in front of each shared folder. It owned the SQLite file and served each agent's copy over NFS, a network file protocol. One week after we retired orlop, we designed a new gateway. Tests found open problems in revoking access, proxy restarts and recovery.

Why did we replace JuiceFS even after moving to Firecracker?

On September 25 we moved agent sessions to Firecracker microVMs, small virtual machines with their own Linux kernel. Storage was the first reason we wrote down: with a real kernel, JuiceFS uses normal FUSE without the gVisor patches. MicroVMs fit fewer agents on a node, and cost was not among our written reasons.

The patches to the JuiceFS client, Litestream and our mount supervisor had nothing to do with gVisor, so Firecracker did not remove them. Between August 13 and September 29, 2026, we tagged 48 versions of our JuiceFS fork. Not all of them reached production.

On September 30 we decided to replace JuiceFS. Our decision record gives one reason: we did not want to keep maintaining it. Our own written analysis from the same day recommended keeping JuiceFS for existing agents and only evaluating a replacement. We overruled it.

The patches all served one goal: keeping a live, mounted filesystem and its replicated metadata consistent inside a sandbox. They touched four layers: the gVisor runtime, the JuiceFS client, Litestream and our mount supervisor. The sharing gateway would have been a fifth.

Our design notes from that day list what the product needs: independent copies, saved versions, and syncing that the platform does for the user. None of that needs a live filesystem shared over the network.

What replaced JuiceFS, and what did we give up?

Workspaces replaced JuiceFS. Each agent works on a local disk on the server that runs its microVM. During a run, the platform saves a version every 60 seconds and again at the end. Each save is a read-only revision in object storage, made with restic, an open-source backup tool. Agents that share a Workspace each get their own copy. The platform accepts an agent's result only if no other result landed first, so one agent cannot silently overwrite another. How we store AI agent files explains this design.

We gave up continuous replication. A crash can lose roughly the last minute of work, plus the time the save takes. Unsaved work must fit on the server's local disk. The restic we run is also our own fork.

Moving existing agents off JuiceFS is a separate job, and it was not finished when we wrote this.

If you are building agent storage

First ask whether your agents must see each other's writes while they run. If they do not, independent copies and saved versions may be enough. Then ask:

  1. How many seconds of work can a crash lose, and does your save interval meet that?
  2. Does git work inside your sandbox on the mounted disk, and how long does a checkout take?
  3. How many forks will you carry, and who updates them?