Skip to main content
The Airtable VFS exposes the bases a personal access token can reach as a read-only filesystem mounted at a prefix such as /airtable/. Writes go through the airtable CLI, which takes the same config. For token setup, see Airtable Setup.

Config

Fields marked secret are redacted in snapshots. Unknown keys are refused, so a misspelled base_ids fails loudly instead of widening the mount to every base.

VFS.md

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

Virtual Filesystem

VFS Layout

/<path>
  • ls a directory first to find exact names: the name part of a segment is sanitized, the id after the last __ is exact.
  • A records.jsonl line is a normalized record: record_id, created_time and fields, keyed by field name with values as Airtable returns them. table.json gives each field’s type.
  • Airtable omits empty cells, so a missing key means empty, a false checkbox included. A link field is a list of record ids; an attachment URL expires two hours after it was read.
  • records.jsonl lists in the API’s own order; a view file applies the view’s filter and sort.
  • A file over max_read_records records stops with File too large after that many, while head -n N fetches just N records.
  • The airtable CLI, if installed, reaches what a file cannot: server-side filters (airtable record list --formula or --view), one record by id (airtable record get) and comments (airtable comment list).

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.
Names are sanitized (Ops / Finance becomes Ops_Finance); the id after the last __ is exact. List a directory to discover names rather than building them.
  • base.json holds the base id, name, the token’s permission level, and the table list.
  • table.json holds the typed field schema, with each field’s options (select choices, number precision, link targets), and the saved views.
  • records.jsonl holds one record per line: {"record_id", "created_time", "fields"}, with fields keyed by field name and valued exactly as Airtable returns them.
  • views/<view>.jsonl holds the records the view shows, filtered and ordered by the view.

Reading Records

  • head -n N fetches N records. The line count is pushed into Airtable’s maxRecords, so the first lines of a large table cost one request.
  • A full read is bounded. A file holding more than max_read_records records ends with GNU’s File too large (cat: <path>: File too large), rather than paging for minutes at 5 requests per second. cat and grep print each page of records as it arrives, so the first max_read_records records come before the error, and a reader that stops first (head -c 100, grep -l) stops the paging and never reaches it. Every command reports it per file and moves on, so grep -l x a b still answers for the files under the cap. Use head, a view, or raise the cap.
  • Order. records.jsonl follows the API’s own order, which Airtable calls arbitrary but keeps stable; a view file applies the view’s sort.
  • Empty cells are absent. Airtable omits empty values from a record, including a false checkbox, so a missing key means empty.
  • Links and attachments. A linked-record field is a list of record ids. An attachment URL expires two hours after it was read, so re-read the record before downloading.
  • Sizes. base.json and table.json report their exact size. Record files are size-unknown until read, which is what ls -l and stat show.
  • Freshness. Records are never served from the file cache; the listings of bases, tables, and views are cached for the index TTL.

Integration

What Airtable answers through its own API, so fewer files are read. Integration explains each command. For one plain text in a records.jsonl or a view’s file, grep and rg ask Airtable for the records that may hold it, with a filterByFormula that searches the record id and each text, select, email, url and phone cell, lowercased, and search those records instead of the whole table, in the order a plain read lists them. Number, date and checkbox cells hold no word to search. A link, AI text or attachment cell holds no space outside the text a formula reads of it, so a table with one is searched for a text with a space and read for a single word. The file is read as usual for a table with a collaborator, lookup, rollup or formula field, for a text a field name holds, or when more than max_read_records records match. Since only the matching records are fetched, a table too large to read can still be searched when the output shows no line numbers or context.

Rate Limits

Requests are spaced to requests_per_second per base. A 429 that says RATE_LIMIT_REACHED is retried after Airtable’s 30 second penalty; a 429 for an exhausted monthly quota is reported at once, because waiting cannot fix it.

Writing Records

A record write is not a file write, so the mount refuses one and the airtable CLI makes it. The CLI names a base, a table and a record by id: take them from the mount’s directory names, after the last __ (Product_Roadmap__appRoadmapBase001 is appRoadmapBase001), and a record’s from its record_id. A records.jsonl line is the CLI’s stdin shape, so an edit pipes straight back:
The CLI also reaches what a file cannot: server-side filters (airtable record list --formula or --view), one record by id (airtable record get), and comments (airtable comment list, airtable comment add).