Skip to content

FileAccess

Sandboxed file I/O restricted to a single directory (typically workspace/data/). Allows scripts and AI to read and write files without exposing the full filesystem.

The driver exposes a small action surface — openText, openBinary, list, mkdir — that returns path-bound handles for the actual read/write/append/delete work. Binding the path once and calling methods on the handle keeps script bodies short and reduces the AI system prompt.

Safety gate

This driver ships with requiresSafetyGates: false — FileAccess operations bypass the safety gate entirely and no audit rows are written. Workspace-state write-locking (Sandbox mode / EULA) still applies. See Per-driver opt-out.

Properties

PropertyTypeAccessDescription
basePathstringRResolved absolute base path
existsboolRWhether the base directory exists

Actions

ActionArgsDescription
openTextpath, delimiter?Returns a TextFileHandle for read/write/append (string or array)
openBinarypathReturns a BinaryFileHandle for base64 I/O
listpath?Returns { files, dirs } for a directory (default: root)
mkdirpathCreate a directory (recursive, idempotent)

delimiter for openText defaults to ",". Pass "\t" for TSV or any other delimiter you need. The openText(path, { delimiter: ";" }) object form is also accepted — the trailing-dict positional merge folds it into the args.

Config Options

OptionTypeDefaultDescription
basePathstringRequired. Root directory for all file operations
maxFileSizeMBint10Maximum file size in MB for read/write
createIfMissingbooltrueCreate base directory if it doesn't exist

TextFileHandle

Returned by openText(path, delimiter?). Binds a single path so subsequent calls don't repeat it:

javascript
const fa = connector("fileaccess");
const log = fa.openText("runs/temps.csv");

log.write("t,T\n");                 // overwrite (creates parent dirs)
for (let t = 0; t < 10; t++) {
  log.append([t, dut.temperature]); // → 0,21.4\n  (array → CSV row)
  await delay(1000);
}

log.size;                           // bytes (0 if missing)
log.exists;                         // bool
log.info();                         // { name, size, created, modified, extension }
log.read();                         // full text
log.readLines();                    // string[]
log.rename("runs/done.csv");        // updates the handle in place
log.delete();                       // idempotent — returns false if missing
MemberKindDescription
pathpropertyThe sandbox-relative path (forward-slashed)
existspropertytrue if the file exists
sizepropertyFile size in bytes (0 if missing)
read()methodRead as UTF-8 text
readLines()methodRead as UTF-8 and split into lines
write(content)methodOverwrite. String or array (joined as a CSV row + \n)
append(content)methodAppend. String or array. null / undefined is a no-op
delete()methodRemove the file. Idempotent — returns false if missing
rename(newPath)methodRename / move within the sandbox; updates the handle
info()method{ name, size, created, modified, extension }

Array → CSV row

Passing a JS array to write or append joins the cells with the handle's delimiter and appends \n. Cells containing the delimiter, a double-quote, CR, or LF are wrapped in "…" and internal " are doubled (RFC 4180). Numbers format with invariant culture, so a host running under nl-NL doesn't turn 2.5 into "2,5" and collide with the comma delimiter.

javascript
const f = fa.openText("data.csv");
f.append([1, 2.5, "plain"]);          // → 1,2.5,plain
f.append([3, 4, "has, comma"]);       // → 3,4,"has, comma"
f.append([5, 6, 'has "quote"']);      // → 5,6,"has ""quote"""

For TSV:

javascript
const t = fa.openText("data.tsv", "\t");
t.append([1, 2, "tab\tseparated"]);   // tab cells are quoted because they contain the delimiter

BinaryFileHandle

Returned by openBinary(path). Read/write are base64-string based, matching what cam.snapshot() and similar drivers produce.

javascript
const img = fa.openBinary("snapshots/frame.jpg");
img.write(cam.snapshot());            // accepts a base64 string
const b64 = img.read();
img.size;                             // bytes on disk (not base64 length)
img.delete();
MemberKindDescription
path, exists, sizepropertiesSame shape as TextFileHandle
read()methodReturns base64-encoded bytes
write(base64)methodOverwrite. Accepts a base64 string
delete()methodIdempotent — returns false if missing
rename(newPath)methodRename / move within the sandbox
info()method{ name, size, created, modified, extension }

Handles obey the same sandbox boundary, size limits (maxFileSizeMB), and workspace.file.changed notifications as the action layer. Methods are synchronous — no await needed.

Security

All file paths are validated to prevent directory traversal attacks. Operations are confined to the configured basePath — you cannot read or write files outside it.

Example: CSV measurement log

javascript
const fa  = connector("fileaccess");
const psu = connector("psu");

const f = fa.openText(`runs/${timestamp().replace(/[:.]/g, "-")}.csv`);
f.write("I_set_mA,V_measured\n");

for (let i = 0; i <= 350; i += 10) {
  psu.current_set = i / 1000;
  await delay(100);
  f.append([i, psu.measured_voltage]);
}
log.info(`Saved ${f.path} (${f.size} bytes)`);

CSV output is chart-viewable

Files written with a .csv or .tsv extension open as an interactive line chart when clicked in the File Explorer. See the CSV Charts section of the UI tour.

Open tabs refresh automatically

Any FileAccess write you do touches a workspace.file.changed notification. Tabs viewing that file reload on their own — a .csv chart grows row-by-row while a script appends to it, no close-and-reopen needed. Tabs with unsaved edits are skipped so in-progress work isn't clobbered.

Example: list a directory

javascript
const fa = connector("fileaccess");
const { files, dirs } = fa.list("runs");
log.info(`${files.length} files, ${dirs.length} subdirs`);

Muxit — Hardware Orchestration Platform