Skip to main content
The Gmail VFS exposes a Gmail account as a virtual filesystem mounted at some prefix such as /gmail/. For Google OAuth setup, see Google Workspace Setup.

Config

Fields marked secret are redacted in snapshots.

VFS.md

The VFS.md an agent reads with Gmail mounted at /<path>.

Virtual Filesystem

/<path> layout

Supported Unix Commands for VFS

Unix commands work on each path as on a local filesystem, as far as the path supports them:

Limitations of Unix Commands for VFS

Where a path differs from a local filesystem:Run man <cmd> or <cmd> --help for one command’s usage.
Example:
Label directories appear at the root. System labels use the Gmail label ID (e.g., INBOX, SENT, STARRED). User-created labels use their label name as is.

Date Directories

Inside each label, messages are grouped into date subdirectories formatted as YYYY-MM-DD. The date is derived from the message’s internalDate (epoch milliseconds) converted to a calendar date.

Message Files

Each message is stored as a .gmail.json file. The filename shape is:
Subjects are sanitized for filesystem safety and truncated when necessary. The message ID is embedded after __ and before .gmail.json.

Attachments

Messages that have attachments get a companion subdirectory with the same base name (without .gmail.json). Decoded attachment files are placed inside:

Cache

The Gmail VFS uses IndexCacheStore (same as Slack, Discord, and other mounts). Index entries store label IDs, message IDs, and message metadata. File bytes go through the workspace file cache.

Example

See examples/python/vfs/gmail/gmail.py for the full working example.

Finding IDs

VFS-specific commands require message IDs. These can be extracted from the filesystem:

Working with Large Labels

Labels with many messages are split into date directories. A bare ls of a label lists the days of its 50 most recent messages; a glob over the date names (ls /gmail/INBOX/2026-03-*) or a date directory by name reaches older days. Tips for efficient access:

Shell Commands

Standard commands available on the mounted Gmail tree: Acting on Gmail (send, reply, forward, triage, raw API calls) goes through the gws CLI when installed.

Integration

What Gmail answers through its own API, so fewer files are read. Integration explains each command. The listing keeps each message’s text, and grep -r and rg read only the messages whose text holds the pattern’s text in any case, printing what reading every message would. Listing a label already fetches its messages in full, so this asks Gmail nothing more and saves the second fetch of each message it rules out. Gmail’s own search is not used: it reads the HTML part of a message and can miss a word of the plain-text body a .gmail.json holds, such as one inside a link. Attachments are always read, and so is every message for a text that is not ASCII, or that may be part of the labels field (inbox, STARRED, Label_1, abel), since a message’s labels change after the listing kept its text. With walk_limit: -1 in the mount’s "@all" command limit, the listing keeps no message text, and every message is read.