FileSystem Module
The FileSystem interface gives your agent path-keyed file storage. POSIX-inspired semantics: paths are forward-slash strings, readFile / writeFile work with Uint8Array, missing paths throw, recursive operations are opt-in.
All v1 providers implement fs.
Interface
interface FileSystem {
readFile(path: string): Promise<Uint8Array>;
writeFile(path: string, data: Uint8Array | string): Promise<void>;
ls(path: string): Promise<FileEntry[]>;
glob(pattern: string): Promise<string[]>;
grep(pattern: string, opts?: GrepOptions): Promise<GrepResult[]>;
stat(path: string): Promise<FileStat>;
rm(path: string, opts?: { recursive?: boolean }): Promise<void>;
mkdir(path: string, opts?: { recursive?: boolean }): Promise<void>;
watch?(path: string, cb: (event: FileEvent) => Promise<void>): Promise<() => void>;
}
interface FileEntry {
readonly name: string;
readonly path: string;
readonly type: 'file' | 'directory' | 'symlink';
readonly size?: number;
}
interface FileStat {
readonly path: string;
readonly type: 'file' | 'directory' | 'symlink';
readonly size: number;
readonly mtime?: Date;
}
interface GrepOptions {
readonly path?: string; // search root; defaults to provider workspaceDir
readonly ignoreCase?: boolean;
readonly includeGlob?: string;
readonly maxResults?: number;
}
interface GrepResult {
readonly path: string;
readonly lineNumber: number; // 1-indexed
readonly line: string;
}watch is optional — providers that support filesystem notifications populate it; others omit. v1 providers do not implement watch.
Per-method semantics
readFile(path)
Returns the file contents as Uint8Array. Throws if the file doesn't exist (the auto-injected tool decodes to text via UTF-8).
writeFile(path, data)
Accepts Uint8Array or string. Strings are written as UTF-8. Creates the file if it doesn't exist; overwrites if it does. Provider-specific behavior on parent directories — most providers create them implicitly, but check the per-provider page if you depend on this.
ls(path)
Returns direct children of a directory. Throws if the directory doesn't exist. The size field is populated for files; omitted for directories.
glob(pattern)
Returns paths matching a glob pattern. Pattern syntax is provider-specific (most use shell-style globs like **/*.ts). The auto-injected tool projects to string[].
grep(pattern, opts?)
Returns line-matching entries. pattern is a regex SOURCE, not a literal string — common gotcha. To match a literal a.ts, escape: a\\.ts. The framework's grep shells out to provider-native search where possible; otherwise it walks files reading + matching client-side.
opts.path scopes the search; opts.ignoreCase adds the i flag; opts.maxResults caps results client-side; opts.includeGlob is reserved (not yet enforced in v1).
stat(path)
Returns metadata for a file or directory. Throws on missing path. mtime may be omitted if the provider doesn't track it.
rm(path, { recursive? })
Removes a file or empty directory. With recursive: true, removes a directory and all contents. Throws on missing path (no force option in v1).
mkdir(path, { recursive? })
Creates a directory. With recursive: true, creates intermediate directories as needed.
Auto-injected tools
For a workspace named <name> with fs: true:
| Tool | Schema | Returns |
|---|---|---|
workspace__<name>__read_file | { path: string } | { content: Uint8Array, text: string } |
workspace__<name>__write_file | { path: string; content: string } | { ok: true } |
workspace__<name>__edit_file | { path: string; oldText: string; newText: string } | { ok: true } (fails if oldText not found exactly once) |
workspace__<name>__ls | { path: string } | { entries: FileEntry[] } |
workspace__<name>__glob | { pattern: string } | { matches: string[] } |
workspace__<name>__grep | { pattern: string; path?; ignoreCase?; includeGlob?; maxResults? } | { matches: GrepResult[] } |
workspace__<name>__stat | { path: string } | { stat: FileStat } |
workspace__<name>__mkdir | { path: string; recursive?: boolean } | { ok: true } |
workspace__<name>__rm | { path: string; recursive?: boolean } | { ok: true } |
The edit_file tool is a convenience layer — it reads the file, finds oldText (must appear exactly once), replaces with newText, and writes back. Useful for LLM-driven refactors where the model knows the exact context but not the line number.
Capability config
interface FileSystemCapConfig {
/** Reserved in v1 — not yet enforced. */
allowedPaths?: readonly string[];
/** Maximum size for writeFile via the auto-injected tool. */
maxFileSizeMb?: number;
}maxFileSizeMb is enforced inside workspace__<name>__write_file — writes exceeding the limit throw WorkspaceFailedError before reaching the provider.
allowedPaths is reserved namespace — declared but not enforced yet. Future plans will wire it to a PolicyEnforcer provider sub-interface.
Provider support matrix
| Provider | fs supported |
|---|---|
| In-Memory | ✅ |
| Local Bash | ✅ |
| Cloudflare Filestore | ✅ |
| Cloudflare Sandbox | ✅ |
All four providers implement the full FileSystem interface.
Source
- Interface:
packages/core/src/workspace/types/modules/fs.ts - Tool injection:
packages/core/src/workspace/tool-injection.ts(search formakeFsTools)