Default Tools — Filesystem¶
The 10 tools in default-tool-specs-builtin-fs.json are the safety.fs surface as ready-to-call tools — a small shell-style filesystem pipeline covering read, list, stat, grep, slice, sort, cut, find, and write. All paths are resolved against the per-app base path (TOOL_STUDIO_FS_BASE, default ${user.home}); any path whose normalize() lands outside the base is rejected before any I/O.
Because they ride on java.nio.file.Path / Files, separator handling (/ vs \), case folding, and symlink semantics are normalised at the JVM layer — these tools behave identically on macOS, Windows, and Linux. See Tool Studio: Cross-platform by design for the mechanics, and Tool Studio: Filesystem mode for the read-only / read-write sandbox split.
The 10 filesystem tools¶
Reads a UTF-8 text file from disk and returns its contents as a single string.
Params path
Env —
More detail
All paths are resolved relative to the playground's configured filesystem base path; anything outside it is rejected. Uses safety.fs.readText().
Parameters
| Param | Type | Req | Description |
|---|---|---|---|
path |
STRING |
✓ | Relative path inside the FS base directory |
Sandbox — Sandbox needs fileRead (L3). Paths resolve against TOOL_STUDIO_FS_BASE (defaults to ${user.home}).
JS source
/**
* Reads a UTF-8 text file inside the playground's FS base directory.
*
* Path is resolved RELATIVE to the base path (which is set via
* `spring.ai.playground.tool-studio.fs.base-path` / TOOL_STUDIO_FS_BASE
* env, defaulting to the user's home directory). Anything attempting
* to escape the base (e.g. `../`) is rejected by safety.fs.
*
* Uses host helper: safety.fs.readText.
*/
if (path == null || path === '') throw new Error('path required');
return safety.fs.readText(path);
Lists the immediate entries (files and subdirectories) of a directory under the FS base path. Returns an array of relative names (not full paths). Uses safety.fs.list().
Params dir
Env —
Parameters
| Param | Type | Req | Description |
|---|---|---|---|
dir |
STRING |
Relative directory path (default '.') |
Sandbox — Sandbox needs fileRead (L3). Paths resolve against TOOL_STUDIO_FS_BASE (defaults to ${user.home}).
JS source
/**
* Lists immediate entries (files + directories) of a directory.
*
* Returned as an array of leaf names — no recursion, no full paths.
* Use `findFiles` for recursive globbing.
*
* Uses host helper: safety.fs.list.
*/
const target = (dir == null || dir === '') ? '.' : dir;
return safety.fs.list(target);
Returns size, last-modified timestamp, and a directory flag for a path inside the FS base. Uses safety.fs.stat().
Params path
Env —
Parameters
| Param | Type | Req | Description |
|---|---|---|---|
path |
STRING |
✓ | Relative path inside the FS base directory |
Sandbox — Sandbox needs fileRead (L3). Paths resolve against TOOL_STUDIO_FS_BASE (defaults to ${user.home}).
JS source
/**
* Returns { size, mtime, directory } for a path inside the FS base.
*
* - size — file size in bytes (0 for directories).
* - mtime — ISO timestamp of last modification.
* - directory — true if the path is a directory.
*
* Uses host helper: safety.fs.stat.
*/
if (path == null || path === '') throw new Error('path required');
return safety.fs.stat(path);
Counts the lines in a UTF-8 text file. Uses safety.fs.lineCount().
Params path
Env —
Parameters
| Param | Type | Req | Description |
|---|---|---|---|
path |
STRING |
✓ | Relative path to the file |
Sandbox — Sandbox needs fileRead (L3). Paths resolve against TOOL_STUDIO_FS_BASE (defaults to ${user.home}).
JS source
/**
* Counts lines in a UTF-8 text file inside the FS base.
*
* Uses host helper: safety.fs.lineCount.
*/
if (path == null || path === '') throw new Error('path required');
return safety.fs.lineCount(path);
Returns a slice of lines from a UTF-8 text file (head / tail / range). start is 0-based inclusive, end is 0-based exclusive (Python-style slice). Negative values count from the end of the file. Uses safety.fs.slice().
Params path · start · end
Env —
Parameters
| Param | Type | Req | Description |
|---|---|---|---|
path |
STRING |
✓ | Relative path to the file |
start |
INTEGER |
First line index (0-based inclusive; negatives from end) | |
end |
INTEGER |
End line index (0-based exclusive; negatives from end) |
Sandbox — Sandbox needs fileRead (L3). Paths resolve against TOOL_STUDIO_FS_BASE (defaults to ${user.home}).
JS source
/**
* Returns lines [start, end) from a UTF-8 text file (Python-slice semantics).
*
* - `start` is 0-based and inclusive.
* - `end` is 0-based and exclusive.
* - Negative values count from the end: -1 == size - 1.
* - Missing `start` / `end` defaults to the file's full range.
*
* Uses host helper: safety.fs.slice.
*/
if (path == null || path === '') throw new Error('path required');
return safety.fs.slice(path, start, end);
Sorts the lines of a UTF-8 text file and returns the sorted lines as an array. Options: reverse / numeric / caseInsensitive / unique. Uses safety.fs.sort().
Params path · reverse · numeric · caseInsensitive · unique
Env —
Parameters
| Param | Type | Req | Description |
|---|---|---|---|
path |
STRING |
✓ | Relative path to the file |
reverse |
BOOLEAN |
Sort descending | |
numeric |
BOOLEAN |
Sort lines numerically | |
caseInsensitive |
BOOLEAN |
Ignore case when comparing | |
unique |
BOOLEAN |
Drop duplicate lines |
Sandbox — Sandbox needs fileRead (L3). Paths resolve against TOOL_STUDIO_FS_BASE (defaults to ${user.home}).
JS source
/**
* Sorts a file's lines and returns them as an array.
*
* Options:
* reverse — descending order
* numeric — numeric comparison (otherwise lexical)
* caseInsensitive — compare lowercased
* unique — drop duplicates
*
* Uses host helper: safety.fs.sort.
*/
if (path == null || path === '') throw new Error('path required');
return safety.fs.sort(path, {
reverse: !!reverse,
numeric: !!numeric,
caseInsensitive: !!caseInsensitive,
unique: !!unique,
});
Searches a UTF-8 text file for lines matching a JavaScript regex. Returns an array of matching lines (optionally numbered). Uses safety.fs.grep().
Params pattern · path · caseInsensitive · numbered · limit
Env —
Parameters
| Param | Type | Req | Description |
|---|---|---|---|
pattern |
STRING |
✓ | Regex pattern (JavaScript flavour) |
path |
STRING |
✓ | Relative path to the file |
caseInsensitive |
BOOLEAN |
Match case-insensitively | |
numbered |
BOOLEAN |
Prefix each result with 'N:' (1-based line number) | |
limit |
INTEGER |
Max matches to return (0 = no limit) |
Sandbox — Sandbox needs fileRead (L3). Paths resolve against TOOL_STUDIO_FS_BASE (defaults to ${user.home}).
JS source
/**
* Greps a file's lines against a regex and returns the hits.
*
* Result is an array of matching lines. With `numbered=true` each entry
* is prefixed by its 1-based line number, e.g. "42: TODO fix this".
*
* Uses host helper: safety.fs.grep.
*/
if (pattern == null || pattern === '') throw new Error('pattern required');
if (path == null || path === '') throw new Error('path required');
return safety.fs.grep(pattern, path, {
caseInsensitive: !!caseInsensitive,
numbered: !!numbered,
limit: Number.isInteger(limit) ? limit : 0,
});
Recursively finds files matching a glob inside a directory. Glob supports * and ?. Optional max recursion depth and type filter ('file' or 'dir'). Uses safety.fs.find().
Params dir · glob · maxDepth · type
Env —
Parameters
| Param | Type | Req | Description |
|---|---|---|---|
dir |
STRING |
Relative directory to search from (default '.') | |
glob |
STRING |
Glob pattern (default '*') | |
maxDepth |
INTEGER |
Max recursion depth (0 = unlimited) | |
type |
STRING |
'file' | 'dir' | omit for both |
Sandbox — Sandbox needs fileRead (L3). Paths resolve against TOOL_STUDIO_FS_BASE (defaults to ${user.home}).
JS source
/**
* Recursively finds entries matching a glob inside a directory.
*
* - Glob accepts `*` and `?` wildcards (POSIX glob, NOT regex).
* - maxDepth limits recursion; 0 means unlimited.
* - type='file' / 'dir' filters; omit to return both.
*
* Uses host helper: safety.fs.find.
*/
const target = (dir == null || dir === '') ? '.' : dir;
const pattern = (glob == null || glob === '') ? '*' : glob;
return safety.fs.find(target, pattern, {
maxDepth: Number.isInteger(maxDepth) ? maxDepth : 0,
type: (type === 'file' || type === 'dir') ? type : null,
});
Extracts selected fields from each line of a delimited file (CSV/TSV/etc.). Uses safety.fs.cut(). 1-based field numbers, comma-separated alternatives via the array.
Params path · fields · delimiter · regex
Env —
Parameters
| Param | Type | Req | Description |
|---|---|---|---|
path |
STRING |
✓ | Relative path to the file |
fields |
ARRAY |
✓ | Array of 1-based field indices to keep, e.g. [1, 3] |
delimiter |
STRING |
Field delimiter character or regex (default '\t' tab) | |
regex |
BOOLEAN |
Treat delimiter as a regex pattern instead of literal |
Sandbox — Sandbox needs fileRead (L3). Paths resolve against TOOL_STUDIO_FS_BASE (defaults to ${user.home}).
JS source
/**
* Extracts selected fields from each line of a delimited file.
*
* - `fields` — 1-based field indices to keep (array). [1, 3] picks columns 1 and 3.
* - `delimiter` — single character (literal) OR a regex pattern when `regex=true`.
* Defaults to tab (\t).
*
* Uses host helper: safety.fs.cut. Each returned row is a delimiter-joined string.
*/
if (path == null || path === '') throw new Error('path required');
if (fields == null) throw new Error('fields required');
const fieldArr = [];
for (const f of fields) fieldArr.push(Number(f));
return safety.fs.cut(path, {
fields: fieldArr,
delimiter: (typeof delimiter === 'string' && delimiter.length > 0) ? delimiter : null,
regex: !!regex,
});
Writes a UTF-8 text file inside the FS base path (creating parent directories as needed). Overwrites any existing file. Requires fileWrite permission on the sandbox.
Params path · content
Env —
Parameters
| Param | Type | Req | Description |
|---|---|---|---|
path |
STRING |
✓ | Relative path to write |
content |
STRING |
✓ | Full text content to write (UTF-8) |
Sandbox — Sandbox needs fileWrite (L4). Paths resolve against TOOL_STUDIO_FS_BASE; the helper auto-creates parent directories.
JS source
/**
* Writes a UTF-8 text file inside the FS base directory.
*
* - Overwrites any existing file at `path`.
* - Path is resolved RELATIVE to the FS base; escape attempts are rejected.
* - This tool needs the `fileWrite` sandbox permission (set on the spec).
*
* Uses host helper: safety.fs.writeText.
*/
if (path == null || path === '') throw new Error('path required');
if (content == null) throw new Error('content required');
safety.fs.writeText(path, String(content));
return { ok: true, path, bytes: new TextEncoder().encode(String(content)).length };
Composition patterns (shell-style filesystem chains)¶
These ten tools mirror the standard Unix-shell pipeline shape, but every step is a JSON-returning function so the agent can reason between calls:
- Read → filter → trim → save —
listDir(dir)→grepFile(pattern, path)→sliceFile(path, start, end)→writeTextFile(outPath, content). The canonical "summarise recent errors from a log directory" flow. - Find → cut → ETL —
findFiles(dir, glob='*.csv')→ loop withcutFileFields(path, fields=[1,3])to project a directory of CSVs into one structured dataset. - Sort dedupe → count —
sortFile(path, numeric=true, unique=true)→lineCount(path)to deduplicate a numeric stream in place and report the resulting size. - Stat-first guard —
statFile(path)→ branch onsize/lastModified→ only run the rest of the pipeline if the file changed since the last run.
Tutorial 8: Default Tool Recipes walks the Read → filter → trim → save chain end-to-end as summariseRecentLogs.
Keys & secrets¶
One configuration value, no real secrets.
| Variable | What it does | Default | Where to set |
|---|---|---|---|
TOOL_STUDIO_FS_BASE |
Per-app safety.fs base path — every path resolved against it; normalize() rejects any escape. |
${user.home} |
Launcher Environment Variables card, or export TOOL_STUDIO_FS_BASE=/path before launch |
The File Toolkit preset opts every read tool into fileRead automatically; writeTextFile requires fileWrite (L4) which you enable per-tool in the Sandbox & Capabilities pane — see Tool Studio: Filesystem mode.
→ Tool Studio: Filesystem mode — fileRead / fileWrite semantics and base-path enforcement.
→ Index — overview of all 86 default tools and the five reference pages.