Skip to main content

Overview

The StorageClient is the Room API for room-scoped files and folders. Use it to store shared inputs, outputs, artifacts, and attachments that humans, agents, and services in the same room need to read or write.

Why use the Storage API?

  • Share files between people, agents, and deployed services without wiring separate object storage access.
  • Store outputs such as reports, logs, generated media, or intermediate artifacts.
  • Download file contents directly or get a downloadable URL when you need to hand a file to another system.

How it works

Paths are relative to the room storage root. Opening a file returns a handle; writes become visible when you close that handle. The API also emits file.updated and file.deleted events so other participants can react to changes.
Current implementation note: the repo includes both local filesystem and GCS-backed storage providers. Deployed services can also mount room storage into the filesystem. The Room Storage API is the stable contract; bucket-mount details belong to service/runtime docs rather than the core API contract.

Permissions and grants

open/write/close and download/download_url require a storage grant on the participant token for the target path. Storage grants are path-based, which lets you give a service access to only part of room storage. In the current server implementation, list, exists, stat, and delete are not gated by storage grants.

CLI and SDK availability

  • CLI: file operations are available under meshagent room storage ....
  • Python, JavaScript/TypeScript, Dart, and .NET: helper methods are shown below.

Events

The storage system emits two types of events:
  • file.updated
    Triggered when a file is created or updated. Python and .NET handlers receive path and participant_id. JS/TS and Dart handlers receive a FileUpdatedEvent with .path.
def on_file_updated(path: str, participant_id: str):
   print(f"File updated: {path} by {participant_id}")

room.storage.on("file.updated", on_file_updated)
  • file.deleted
    Triggered when a file is deleted. Python and .NET handlers receive path and participant_id. JS/TS and Dart handlers receive a FileDeletedEvent with .path.
def on_file_deleted(path: str, participant_id: str):
   print(f"File deleted: {path} by {participant_id}")

room.storage.on("file.deleted", on_file_deleted)
You can remove an event handler with:
room.storage.off("file.updated", on_file_updated)
room.storage.off("file.deleted", on_file_deleted)

API Methods

Below is a summary of the primary methods. Each method is asynchronous, so you should await the call.

exists(path)

Description
Checks if a file or folder exists at the given path.
Parameters
  • path (str): The path to check.
Returns
  • (bool): True if the file or folder exists; False otherwise.
Example:
meshagent room storage exists \
  --room myroom \
  room://folder/data.json

stat(path)

Description
Fetch basic metadata (exists, folder flag, created/updated timestamps) for a file or folder.
Parameters
  • path (str): The path to inspect.
Returns
  • StorageEntry | None: Entry when present; None if not found.
The server returns name, is_folder, created_at, and updated_at fields. SDKs that expose stat parse timestamps into native datetime types. Example:
entry = await room.storage.stat(path="folder/data.json")
if entry:
    print(entry.name, entry.is_folder, entry.created_at, entry.updated_at)
  • Availability: Python SDK exposes stat; other SDKs can call the same endpoint via a custom request until a helper is added.

open(path, overwrite=False)

Description
Opens a file for writing. Returns a handle used for subsequent write calls and closing.
If overwrite is True, an existing file at this path will be truncated. Current storage providers truncate on open regardless of overwrite, so check exists or stat before opening if you need to guard against overwrites.
Parameters
  • path (str): The file path to open or create.
  • overwrite (bool, optional): Whether to overwrite if the file already exists. Defaults to False.
Returns
  • Handle Object: An object representing an open file, usable with write and close.
Example:
handle = await room.storage.open(path="files/new.txt", overwrite=True)

write(handle, data)

Description
Writes binary data to an open file handle. You can call write multiple times to stream chunks before closing.
Parameters
  • handle (file handle): The handle returned by open.
  • data (bytes): The data to write.
Returns
  • None
Example:
data_to_write = b"Sample data"

await room.storage.write(handle=my_handle, data=data_to_write)

close(handle)

Description
Closes an open file handle, ensuring all data has been written. A file.updated event is emitted on close.
Parameters
  • handle (file handle): The handle to close.
Returns
  • None
Example:
await room.storage.close(handle=my_handle)

download(path)

Description
Retrieves the content of a file from the remote storage. This loads the entire file into memory; use download_url for large files or streaming.
Parameters
  • path (str): The file path to download.
Returns
  • File-like Response: Contains the file’s raw data, typically accessible through a .data property.
Example:
meshagent room storage cp \
  room://files/data.bin \
  ./data.bin \
  --room myroom

download_url(path)

Description
Requests a downloadable URL for the specified file path, which can be used to fetch the file directly (e.g., via HTTP). The exact protocol or format of the returned URL may vary, and may be a signed URL if the backing storage provider supports it.
Parameters
  • path (str): The file path to retrieve a download URL for.
Returns
  • (str): A URL string you can fetch with your own HTTP or other suitable client.
Example:
url = await room.storage.download_url(path="files/report.pdf")
print("Download the file from:", url)

list(path)

Description
Lists the contents of a folder, returning file and subfolder names along with a flag indicating if each entry is a folder. The server also returns created_at and updated_at timestamps; the Python SDK exposes them on StorageEntry.
Parameters
  • path (str): The folder path to list.
Returns
  • (list): A list of entries, each containing a name and is_folder property. Timestamps are available in SDKs that surface them.
Example:
meshagent room storage ls \
  --room myroom \
  room://some_folder

delete(path)

Description
Deletes a file or folder at the given path. A file.deleted event is typically emitted afterward. To delete a folder, pass recursive=True (Python) or call the raw storage.delete request with the recursive flag.
Parameters
  • path (str): The file path to delete.
  • recursive (bool, optional): Set True to delete folders recursively (Python helper or raw request).
Returns
  • None
Example:
meshagent room storage rm \
  --room myroom \
  room://folder/old_file.txt

Example Workflow

A common use case:
  1. Check if a file exists.
  2. Create and write data if it doesn’t exist.
  3. Later, download the file to verify or use the data.
  4. Delete the file when it’s no longer needed, reacting to the file.deleted event.
# Check existence
exists = await room.storage.exists(path="example.txt")
if not exists:
    # Create it
    handle = await room.storage.open(path="example.txt")
    await room.storage.write(handle=handle, data=b"Hello, Storage!")
    await room.storage.close(handle=handle)

# Download content
response = await room.storage.download(path="example.txt")
print("Downloaded content:", response.data)

# Delete it
await room.storage.delete("example.txt")

This sequence demonstrates basic creation, reading, and deletion flows within a single session.