mountable.io

LlamaIndex snapshots

Save a LlamaIndex index on mountable.io, then download and load its checked JSON files in a fresh worker.

mountable.io is a persistent filesystem for AI agents. A LlamaIndex worker can finish writing an index locally, upload its files, and exit. The next worker downloads those files into a fresh local directory and loads the index there.

mountable.io maintains this community recipe, separately from LlamaIndex. It follows LlamaIndex's documented persist/load API. It stores a frozen index snapshot. An online vector database is a different tool for indexes that many writers keep changing.

Set up

Use Python 3.11 or newer and uv. The example pins llama-index-core==0.14.25 and mountable-sdk==0.3.0, with a lockfile. It indexes two synthetic documents using fixed local embeddings. It retrieves a document without a hosted model or embedding API key.

You need an existing mountable.io account with a saved payment method, an existing filesystem and an API key that can access it. Set MOUNTABLE_API_KEY in your private environment. Your trusted backend chooses the filesystem and run id. Neither comes from a model or an untrusted caller.

git clone https://github.com/writeitai/mountable.git
cd mountable/examples/llamaindex-snapshot
uv sync --locked
export FS_ID="your-filesystem-id"
export RUN="snapshot1"

Choose a new run id for every snapshot: 1–40 lowercase letters, digits or hyphens, starting with a letter or digit. Files live at llamaindex/<run>/.

Save the snapshot

uv run python snapshot.py publish --filesystem "$FS_ID" --run "$RUN"

The command persists the index locally. Once all files are closed, it uploads docstore.json, index_store.json, graph_store.json, default__vector_store.json and image__vector_store.json. It then uploads manifest.json, containing each file's size and SHA-256.

Every upload is create-only. A second publish to the same path refuses to replace the earlier files. The manifest is written last, but the six writes are separate operations, not a transaction. An interrupted upload can leave partial files. Inspect the prefix, clean up and choose a new run id before trying again after a timeout.

Save the printed manifest_sha256 in trusted job metadata outside the snapshot prefix. It lets the next job check the manifest itself.

Load it in a fresh process

Copy the publisher's 64-character digest into MANIFEST_SHA256:

export MANIFEST_SHA256="paste-the-digest-from-publish"
uv run python snapshot.py query --filesystem "$FS_ID" --run "$RUN" \
  --manifest-sha256 "$MANIFEST_SHA256"

This new process opens a read-only SDK handle. It checks the manifest's digest, format, LlamaIndex version and exact file names. It then checks all five file sizes and hashes in an empty temporary directory before calling StorageContext.from_defaults and load_index_from_storage.

The result is:

The synthetic observatory stores its telescope in the blue dome.

We ran this handoff against production storage. A separate process retrieved that document. Changing an artifact or removing one made the reader refuse to load the snapshot.

The code uses only JSON, with no pickle or archive extraction. Use snapshots from your own trusted publisher. A checksum checks bytes, not the author's identity. Keep dependency versions and the embedding configuration the same when building and loading. The fixed two-dimensional embedding in this recipe proves the handoff; choose a real embedding model for your own documents.

Each artifact is limited to 1 MiB and the manifest to 4 KiB. The SDK buffers downloads before checking them, so keep this example on trusted small data. The files are downloaded locally before LlamaIndex opens them. This recipe does not provide a remote vector-store or fsspec adapter.

Clean up and billing

uv run python snapshot.py cleanup --filesystem "$FS_ID" --run "$RUN"

Cleanup deletes the known file names using their current ETags, then removes empty directories. Coordinate cleanup with readers. It also works after a partial upload.

Storage, downloads and file operations follow the usage prices. Deleting files does not reverse earlier usage, and retained bytes can remain until garbage collection. This recipe creates no filesystem, account or credits. A filesystem spending cap covers mountable.io usage, not a model provider's bill.

See the example's README for the offline tests and Python SDK docs for other file operations.