/notion/.
For API key setup, see Notion Setup.
Config
Fields marked secret are redacted in snapshots.
VFS.md
The VFS.md an agent reads with Notion mounted at/<path>.
- Rendered
- Raw
Virtual Filesystem
VFS Layout
/<path>
page.jsonholds the page’s metadata, its body rendered as Markdown and its raw blocks (nested blocks underchildren).- A database is a container plus one or more data sources.
database.jsonholds the container’s identity and itsdata_sourcesstubs,data_source.jsonthe typed property schema, androws.jsonlthe rows, one JSON line each: the row page’spage.jsonwithout the body, pluspath, thatpage.json’s path below the data source directory. Row directories are not listed; open one by its path. - Titles are sanitized. Don’t construct paths:
lsthe parent directory, or take a row’spathfromrows.jsonl. ntntakes ids as positional operands, not flags:ntn pages get <page-id>,ntn datasources query <data-source-id>,ntn datasources resolve <database-id>.
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.pages/ hierarchy mirrors Notion’s standalone page tree. Each page
directory contains a page.json with the page metadata and content, and
child pages appear as nested directories.
The databases/ hierarchy is one level deeper than the page tree,
because the 2025-09-03 API generation split a database into a
container plus one or more data sources. The column schema and the
rows both live on the data source: data_source.json and rows.jsonl.
The name stutters for a single-source database because Notion names the
auto-created data source after its database; that disappears the moment
a database holds two.
A data source lists its rows as one file, not as a directory each. A
query answers a hundred rows’ cells in one call, while every row
directory costs calls of its own to enter, so a grep -r or find over
a large database would cost calls per row. A row is still a page with a
page.json, at <data-source-dir>/<row-title>__<page-id>/page.json: it
is not listed, and its path is on the row’s line in rows.jsonl.
database.json
The container’s identity. It carriesdatabase_id, title, url,
timestamps, parent, archived, is_inline, and the data_sources
stubs that name the directories beneath it. It does not carry
properties: at this API version the column schema lives on the data
source, and GET /v1/databases/{id} no longer returns one.
data_source.json
The typed column schema (Notion’s own property objects), with no rows inline:ntn datasources resolve <database-id>.
rows.jsonl
Every row of the data source, one JSON object per line, in the order the query returns them. A line is the row’spage.json without the body,
which a query does not carry, plus path, where that page.json is
below the data source directory:
page.json
A page, including a database row. Notion blocks render tomarkdown and
stay available raw under blocks; a row’s cell values are under
properties, as Notion’s own property objects, answering to the schema
in the data_source.json one level up:
children key, and
the Markdown renders nested blocks with indentation. A standalone page’s
properties holds only its title, which is what the API returns for
one.
Cache
UsesIndexCacheStore for page metadata. File bytes go through the workspace
file cache.
Integration
What Notion answers through its own API, so fewer files are read. Integration explains each command.Example
Shell Commands
Standard commands available on the mounted Notion tree:
Acting on Notion (creating, editing and trashing pages, querying data
sources, and every route that has no typed verb) goes through the
ntn CLI when installed. Ids are positional: use the
<page-id> / <database-id> / <data-source-id> from a path segment as
the operand.