# Filesystem API URL: /runtime/api/filesystem Runtime supports Node.js, browser, memory, confined fs-compatible, and cross-worker bridge filesystems. ## Filesystem Types [#filesystem-types] **`RuntimeFileSystemBase`** — Base filesystem interface for runtime backends. Aliases the canonical {@link FileSystemProvider} from `@taucad/filesystem` augmented with an optional `watch` subscription. Filesystem backends authored for the runtime (e.g. `fromFsLike`, `fromMemoryFs`, `fromNodeFs`) implement this shape; the runtime upgrades it into a {@link KernelFileSystem} at the worker boundary via the runtime's internal decorator. Paths are canonical and root-relative within the supplied runtime filesystem; `''` refers to that filesystem's root. - **`id`** (`string`, required) - **`capabilities`** (`ProviderCapabilities`, required) - **`supportsHeadListing`** (`true | undefined`, optional) — Explicit opt-in to head-only listing; absent on exact-only legacy providers. - **`readdirWithStats`** (`{ (path: string): Promise; (path: string, options: { readonly content: "head"; }): Promise>>; } | undefined`, optional) — Optional batched listing. Omission returns exact metadata; `head` omits unknown line counts. - **`readFile`** (`{ (path: string): Promise>; (path: string, encoding: "utf8"): Promise; }`, required) - **`writeFile`** (`(path: string, data: Uint8Array | string) => Promise`, required) — Persist a file, creating any missing parent directories. - **`writeFileChecked`** (`((input: Omit) => Promise) | undefined`, optional) — Atomically check current bytes and replace one file when this provider owns a real authority fence. - **`deleteFileChecked`** (`((input: { path: string; preconditions: readonly FileWritePrecondition[]; }) => Promise) | undefined`, optional) — Atomically check current bytes and delete one file under the same authority fence. - **`appendFile`** (`((path: string, data: Uint8Array | string) => Promise) | undefined`, optional) — Append bytes in enqueue order, creating the file and missing parent directories when absent. - **`readdir`** (`(path: string) => Promise`, required) - **`stat`** (`(path: string) => Promise`, required) - **`mkdir`** (`(path: string, options?: { recursive?: boolean; }) => Promise`, required) - **`unlink`** (`(path: string) => Promise`, required) - **`rmdir`** (`(path: string) => Promise`, required) - **`rename`** (`(from: string, to: string) => Promise`, required) - **`exists`** (`(path: string) => Promise`, required) - **`lstat`** (`(path: string) => Promise`, required) - **`getFileMode`** (`((path: string) => Promise) | undefined`, optional) — Read a regular file's Git-compatible executable mode when the backend exposes it. - **`setFileMode`** (`((path: string, mode: FileMode) => Promise) | undefined`, optional) — Apply a Git-compatible regular-file mode without exposing an unrestricted chmod seam. - **`dispose`** (`() => void`, required) - **`readFileStream`** (`((path: string, options?: FileReadStreamOptions) => ReadableStream>) | undefined`, optional) — Optional streaming read. When present, service routes through this instead of buffered readFile. - **`readdirEntries`** (`((path: string) => Promise) | undefined`, optional) — Optional readdir carrying entry kinds. When present, tree walks skip the stat-per-child. - **`refresh`** (`((prefixes?: readonly string[]) => Promise) | undefined`, optional) — Refresh provider projections after an out-of-band mutation. Pass the absolute paths whose subtrees changed to scope the invalidation; omit them to drop everything. - **`observe`** (`((listener: (facts: readonly ExternalChangeFact[]) => void) => Promise<(() => void) | undefined>) | undefined`, optional) — Report this root's own external changes. Declared only by a backend that can observe itself; the authority falls back to bounded snapshot polling for one that cannot, so capability presence — never backend identity — decides how a root is watched (charter D13). Resolves with a disposer, or with `undefined` when observation exists in principle but could not be armed here and polling must cover the root. A rejection means the root has no fallback and its derivatives are stale. - **`watch`** (`((request: RuntimeWatchRequest, handler: (event: RuntimeWatchEvent) => void) => () => void) | undefined`, optional) — Subscribe to filesystem change events for the given paths. Returns an unsubscribe function. Events are filtered server-side. **`KernelFileSystem`** — Enhanced filesystem interface seen inside kernel/bundler/middleware code. Extends the base primitives with higher-level helper methods built from the primitives by the runtime's internal decorator. Provider watch stays on the transport boundary and is not exposed through this kernel-facing facade. Distinct from the consumer-facing opaque `RuntimeFileSystem` value (`#filesystem/runtime-filesystem.js`) produced by `from*` factories and handed to a transport plugin's `client({ fileSystem })`; the transport unwraps the opaque value and upgrades the backing `RuntimeFileSystemBase` inside the runtime worker. Renamed from `RuntimeFileSystem` (R14) to disambiguate from the consumer-facing opaque brand. The `KernelFileSystem` name is exported only from the kernel-author subpath `@taucad/runtime/kernel`; the consumer barrel reserves `RuntimeFileSystem` for the opaque value. All methods operate on paths within the supplied runtime filesystem. - **`id`** (`string`, required) - **`capabilities`** (`ProviderCapabilities`, required) - **`supportsHeadListing`** (`true | undefined`, optional) — Explicit opt-in to head-only listing; absent on exact-only legacy providers. - **`readdirWithStats`** (`{ (path: string): Promise; (path: string, options: { readonly content: "head"; }): Promise>>; } | undefined`, optional) — Optional batched listing. Omission returns exact metadata; `head` omits unknown line counts. - **`readFile`** (`{ (path: string): Promise>; (path: string, encoding: "utf8"): Promise; }`, required) - **`writeFile`** (`(path: string, data: Uint8Array | string) => Promise`, required) — Persist a file, creating any missing parent directories. - **`writeFileChecked`** (`((input: Omit) => Promise) | undefined`, optional) — Atomically check current bytes and replace one file when this provider owns a real authority fence. - **`deleteFileChecked`** (`((input: { path: string; preconditions: readonly FileWritePrecondition[]; }) => Promise) | undefined`, optional) — Atomically check current bytes and delete one file under the same authority fence. - **`appendFile`** (`((path: string, data: Uint8Array | string) => Promise) | undefined`, optional) — Append bytes in enqueue order, creating the file and missing parent directories when absent. - **`readdir`** (`(path: string) => Promise`, required) - **`stat`** (`(path: string) => Promise`, required) - **`mkdir`** (`(path: string, options?: { recursive?: boolean; }) => Promise`, required) - **`unlink`** (`(path: string) => Promise`, required) - **`rmdir`** (`(path: string) => Promise`, required) - **`rename`** (`(from: string, to: string) => Promise`, required) - **`exists`** (`(path: string) => Promise`, required) - **`lstat`** (`(path: string) => Promise`, required) - **`getFileMode`** (`((path: string) => Promise) | undefined`, optional) — Read a regular file's Git-compatible executable mode when the backend exposes it. - **`setFileMode`** (`((path: string, mode: FileMode) => Promise) | undefined`, optional) — Apply a Git-compatible regular-file mode without exposing an unrestricted chmod seam. - **`dispose`** (`() => void`, required) - **`readFileStream`** (`((path: string, options?: FileReadStreamOptions) => ReadableStream>) | undefined`, optional) — Optional streaming read. When present, service routes through this instead of buffered readFile. - **`readdirEntries`** (`((path: string) => Promise) | undefined`, optional) — Optional readdir carrying entry kinds. When present, tree walks skip the stat-per-child. - **`refresh`** (`((prefixes?: readonly string[]) => Promise) | undefined`, optional) — Refresh provider projections after an out-of-band mutation. Pass the absolute paths whose subtrees changed to scope the invalidation; omit them to drop everything. - **`observe`** (`((listener: (facts: readonly ExternalChangeFact[]) => void) => Promise<(() => void) | undefined>) | undefined`, optional) — Report this root's own external changes. Declared only by a backend that can observe itself; the authority falls back to bounded snapshot polling for one that cannot, so capability presence — never backend identity — decides how a root is watched (charter D13). Resolves with a disposer, or with `undefined` when observation exists in principle but could not be armed here and polling must cover the root. A rejection means the root has no fallback and its derivatives are stale. - **`readFiles`** (`(paths: string[]) => Promise>>`, required) — Batch-read multiple files as binary. Default: `Promise.all(paths.map(readFile))`. - **`readdirContents`** (`(directoryPath: string) => Promise>>`, required) — Read all file contents in a directory (skips subdirectories). - **`readdirStat`** (`(directoryPath: string) => Promise`, required) — Get stat information for all entries in a directory. - **`ensureDir`** (`(path: string) => Promise`, required) — Ensure a directory exists, creating parents as needed. Default: `mkdir(path, { recursive: true })`. **`RuntimeFileSystem`** — Opaque consumer-facing filesystem handle. Reaching into the value to inspect the underlying handle is a type error: the brand is unexported, so consumer code cannot construct a matching value. _No properties._ **`FsLike`** — Minimal interface for any fs-compatible object with a `promises` namespace. Matches the shape of `fs` from BrowserFS, memfs, and similar libraries without importing them directly. Uses `ArrayBuffer`-backed bytes at the runtime boundary so transfer ownership remains explicit and does not accidentally include shared memory. - **`promises`** (`{ readFile(path: string, encoding: "utf8"): Promise; readFile(path: string): Promise>; writeFile(path: string, data: Uint8Array | string): Promise; mkdir(path: string, options?: { recursive?: boolean; }): Promise; readdir(path: string): Promise; unlink(path: string): Promise; rmdir(path: string): Promise; rename(oldPath: string, newPath: string): Promise; stat(path: string): Promise; lstat(path: string): Promise; }`, required) — Filesystem methods that receive paths within this already-confined filesystem. Runtime `/` is its root. Kernel I/O methods use the shared entry and event types: `FileEntry`, `FileStat`, `FileStatEntry`, `FileTreeEntry`, and `FileStatus` describe listings and stats; watch callbacks receive `ChangeEvent` values carrying a `ChangeEventStat`. `isRuntimeFileSystem` guards an opaque handle; `isNotFoundError` classifies read failures; `runtimeFileSystemSchema` is the Zod validator for the kernel-facing method surface. ## Constructors [#constructors] | Function | Import Path | Description | | ---------------------------- | ------------------------------------ | --------------------------------------------------------- | | `fromNodeFs(basePath)` | `@taucad/runtime/filesystem/node` | Node.js filesystem rooted at `basePath` | | `fromBrowserFs(root)` | `@taucad/runtime/filesystem/browser` | Browser directory handle used as the runtime root | | `fromMemoryFs(files?)` | `@taucad/runtime/filesystem` | In-memory Map-backed filesystem, optionally seeded | | `fromFsLike(fs)` | `@taucad/runtime/filesystem` | An already-confined virtual filesystem | | `fromFileSystemBridge(open)` | `@taucad/runtime/filesystem` | A fresh rooted bridge connection for each runtime binding | Every constructor establishes the root of the [runtime-path namespace](/runtime/concepts/path-namespaces). Filesystem method arguments are root-relative, so `main.ts` refers to a file beneath the supplied root and `''` refers to the root itself. ## Bridge Types [#bridge-types] **`FileSystemBridge`** — Handle returned by {@link createFileSystemBridge}: same-isolate {@link Port} for bridge clients. - **`port`** (`Port`, required) — Wire-agnostic port for RPC clients in this isolate. - **`dispose`** (`() => void`, required) **`FileSystemBridgeOptions`** — Options for configuring the filesystem bridge message type. - **`messageType`** (`string | undefined`, optional) - **`uiCoalescingWindow`** (`number | undefined`, optional) — Coalescing window for UI-bound fileChanged events (default: 500). Milliseconds. - **`createCoalescer`** (`CoalescerFactory | undefined`, optional) — Factory for creating a change event coalescer. When provided, events from `changeEventBus` are batched before broadcasting to bridge clients. When omitted, events pass through without batching. - **`root`** (`string | undefined`, optional) — The workspace surface: no root, and therefore no view to name. Project mount to expose as `/` for this connection. The root is consumed by the filesystem server when the connection is accepted; it is never forwarded to runtime calls. - **`consumer`** (`RootedBridgeConsumer | undefined`, optional) — Which surface this rooted connection reads; required beside a root (CI2). **`ExposeFileSystemHandle`** — Handle returned by {@link exposeFileSystem} for managing bridge connections and cleanup. - **`cleanup`** (`() => void`, required) - **`activePorts`** (`Set`, required) - **`serverHandles`** (`Map`, required) `fromFileSystemBridge` returns a `FileSystemBridgeConnection`; `BridgePort` and `BridgeServerHandle` support host adapters. ## Bridge Utilities [#bridge-utilities] For cross-worker filesystem access, `@taucad/runtime/filesystem` provides the filesystem-specific authority boundary: | Function | Description | | ------------------------------------------ | --------------------------------------------------------------------------------------------------- | | `exposeFileSystem(handlers, options?)` | Listen in the filesystem-owning worker; expose an authority as `workspaceBridgeService(service)`. | | `openFileSystemBridge(worker, options?)` | Open a fresh scoped connection for `fromFileSystemBridge`; use this for runtime transport wiring. | | `createFileSystemBridge(worker, options?)` | Open a managed filesystem bridge when the current isolate also needs to call filesystem methods. | | `createFileSystemBridgeProxy(bridge)` | Create the validated filesystem proxy from the managed bridge returned by `createFileSystemBridge`. | ## Bridge Usage [#bridge-usage] Trusted host code selects an authority route once and supplies a connection factory. The runtime sees only the rooted project's writable local namespace: ```typescript import { fromFileSystemBridge, openFileSystemBridge } from '@taucad/runtime/filesystem'; const fileManagerWorker = new Worker(new URL('./file-manager.worker.ts', import.meta.url), { type: 'module' }); const fileSystem = fromFileSystemBridge(() => openFileSystemBridge(fileManagerWorker, { root: '/projects/widget', consumer: 'agent' }), ); ``` A `root` always names the surface it serves. There is no default: an absent or unknown `consumer` is refused, and the connection answers `ROOT_UNAVAILABLE`. | `consumer` | Surface | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | `'working-copy'` | The checkout's own files, with no overlays composed above them. Trusted host composition only. | | `'user'` | What a person sees in the file tree: host-written records included, the control plane hidden. | | `'agent'` | What an agent sees: records readable but not writable, the control plane hidden. A runtime that renders agent-authored code names this one too. | Inside runtime, `main.ts`, `.tau/cache/**`, and `node_modules/**` all belong to that rooted capability. The runtime receives no project id or authority-global root and performs no authorization checks; filesystem reachability is the authority boundary. `fromFsLike(fs)` follows the same local-path contract but assumes `fs` is already confined. Use `fromNodeFs(hostRoot)` for raw Node.js access so the adapter can enforce lexical and symlink containment. ## Related [#related] * [Set Up the Filesystem](/runtime/guides/filesystem-setup) * [Worker Model](/runtime/concepts/worker-model) * [Path Namespaces](/runtime/concepts/path-namespaces) * [API: Client](/runtime/api/client) * [API: Types](/runtime/api/types) * [RPC Wire Spec](https://github.com/taucad/tau/blob/main/docs/architecture/rpc-wire-spec.md)