File Access
Listing, reading, and writing files on a node, with the roots you configure, the caps that apply, and what gets refused.
A node can list, read, and write files on the machine it runs on, but only inside folders you name. Everything outside them is refused before it touches disk.
The filesystem.access scope is not granted when you approve a device. This is one of the escalations you opt into deliberately.
Configuring roots
File access is confined to a configured list of root folders. Out of the box that is the user's Desktop, Documents, and Downloads.
An empty roots list denies everything. It is not a wildcard, and it is not "unrestricted". It is the off switch. Setting it to an empty list is the way to keep the scope granted while turning file access off entirely.
Roots live under fileSystemRoots in the node's config file. Note the capital S, and see the configuration file, which also explains why the spelling matters more than it should.
Choose roots as narrowly as the work allows. A node that only needs to drop reports somewhere should have that one folder, not the whole Documents tree.
Containment
A path is fully resolved before it is tested for containment, not after. That means:
~is expanded...segments are collapsed, so a path cannot climb out of a root by walking upward.- Symlinks are followed to their final target, and it is the target that must be inside a root. A link sitting in an allowed folder but pointing somewhere else fails the check instead of escaping through it.
Containment is also tested on a folder boundary rather than a string prefix, so a root of /home/you/work does not accidentally permit /home/you/work-secrets.
On Linux the comparison is case-sensitive, matching the filesystem's own behaviour; on Windows and macOS it is not.
Limits
| Limit | Value | Applies to |
|---|---|---|
| Read size | 512 KB | filesystem.read |
| Write size | 512 KB | filesystem.write |
| Listing length | 500 entries | filesystem.list |
| Binary content | refused | filesystem.read |
| Directory targets | refused | filesystem.write |
A listing that hits the cap comes back flagged as truncated rather than silently short. A read that finds binary content refuses rather than returning something the model would only mangle. These commands are for text.
The three commands
files.list → filesystem.list
Lists entries in a folder inside a configured root.
| Param | Type | Default | Notes |
|---|---|---|---|
path | string | required | Must resolve inside a root |
Returns the entries with their names, sizes, and modified times, plus a flag when the result was truncated at the cap.
files.read → filesystem.read
Reads a text file inside a configured root.
| Param | Type | Default | Notes |
|---|---|---|---|
path | string | required | Must resolve inside a root |
Rated Low risk. Refuses binary content, and refuses anything over the size cap rather than truncating it.
files.write → filesystem.write
Writes a text file inside a configured root.
| Param | Type | Default | Notes |
|---|---|---|---|
path | string | required | Must resolve inside a root |
content | string | required | Subject to the size cap |
Rated High risk, so it raises an approval — once, before anything is written, and delivered to the channel the conversation is actually in rather than only to the Dashboard.
Refuses a directory as its target. It also does not create folders: the parent has to exist already and be inside a root, and that parent is checked separately from the path being written, so a new file cannot be dropped just outside one.
One caveat on "always": in an interactive chat turn, approving a High-risk desktop action can cover further High-risk actions on that machine for the rest of the run, so a second write inside that window may not ask again. That standing consent lasts thirty minutes, belongs to one conversation, is cleared by a Gateway restart, and never extends to a workflow, a scheduled run, a webhook or an MCP call — those ask every time. See plan-level consent.
What this is not
There is no file transfer between the Gateway and a node. These commands read and write in place, on the machine, and the content travels as part of the command result like any other. Moving a large file between machines is not something a node does.
Files on the Sophon server itself are a different thing entirely, reached with different tools. files.* means the user's machine.
Where to go next
- Permissions & Scopes — granting
filesystem.access - Gates, Limits & Audit — the approval a write raises
- Commands & Actions — the rest of the command surface
- Install & Pair a Node — where roots are configured
Commands & Actions
Every command type a node can execute and every action remote.control exposes, with parameters, responses, scopes, and risk.
Desktop Awareness
How an agent finds out what is on your screen and what you were working on, via the on-demand desktop context, the background activity recorder, and the desktop.activity tool.