host:fs
The host:fs module provides file system operations with capability-based access control.
Capabilities
File system access must be declared in manifest.app.toml:
[capabilities.fs]read = ["~/.myapp/*", "./data/*"]write = ["~/.myapp/*"]Glob patterns supported:
*- matches any characters except/**- matches any characters including/~- expands to user’s home directory
Reading Files
readTextFile(path)
Read a file as UTF-8 text:
import { readTextFile } from "host:fs";
const content = await readTextFile("./config.json");const config = JSON.parse(content);readBytes(path)
Read a file as raw bytes:
import { readBytes } from "host:fs";
const data = await readBytes("./image.png");// Returns: Uint8ArrayWriting Files
writeTextFile(path, content)
Write UTF-8 text to a file:
import { writeTextFile } from "host:fs";
await writeTextFile("./output.txt", "Hello, World!");writeBytes(path, content)
Write raw bytes to a file:
import { writeBytes } from "host:fs";
const data = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]);await writeBytes("./binary.dat", data);Directory Operations
readDir(path)
Read directory contents:
import { readDir } from "host:fs";
const entries = await readDir("./src");for (const entry of entries) { console.log(entry.name, entry.is_file ? "file" : "dir");}Returns:
interface DirEntry { name: string; is_file: boolean; is_dir: boolean;}mkdir(path, options?)
Create a directory:
import { mkdir } from "host:fs";
// Create single directoryawait mkdir("./output");
// Create nested directoriesawait mkdir("./path/to/nested", { recursive: true });File Operations
stat(path)
Get file/directory information:
import { stat } from "host:fs";
const info = await stat("./file.txt");console.log(info.size, info.is_file, info.readonly);Returns:
interface FileStat { is_file: boolean; is_dir: boolean; size: number; readonly: boolean;}exists(path)
Check if a path exists:
import { exists } from "host:fs";
if (await exists("./config.json")) { // Load config}remove(path, options?)
Remove a file or directory:
import { remove } from "host:fs";
// Remove fileawait remove("./temp.txt");
// Remove directory recursivelyawait remove("./cache", { recursive: true });rename(from, to)
Rename or move a file/directory:
import { rename } from "host:fs";
await rename("./old-name.txt", "./new-name.txt");await rename("./file.txt", "./archive/file.txt");copy(from, to)
Copy a file:
import { copy } from "host:fs";
await copy("./source.txt", "./destination.txt");File Watching
watch(path)
Watch a file or directory for changes:
import { watch } from "host:fs";
const watcher = await watch("./src");
// Using async iteratorfor await (const event of watcher) { console.log(event.kind, event.paths);}
// Using next() methodwhile (true) { const event = await watcher.next(); if (!event) break; console.log(event);}
// Clean upawait watcher.close();Event shape:
interface FileEvent { kind: string; // "create", "modify", "remove", etc. paths: string[]; // Affected paths}Watcher interface:
interface FileWatcher { id: string; next(): Promise<FileEvent | null>; [Symbol.asyncIterator](): AsyncIterableIterator<FileEvent>; close(): Promise<void>;}Error Handling
All operations throw on error:
import { readTextFile } from "host:fs";
try { const content = await readTextFile("./missing.txt");} catch (error) { if (error.message.includes("not found")) { console.log("File does not exist"); } else if (error.message.includes("permission")) { console.log("Access denied - check capabilities"); }}Complete Example
import { readTextFile, writeTextFile, exists, mkdir, watch} from "host:fs";import { homeDir } from "host:sys";
// Config file pathconst configPath = `${homeDir()}/.myapp/config.json`;
// Ensure directory existsif (!await exists(`${homeDir()}/.myapp`)) { await mkdir(`${homeDir()}/.myapp`);}
// Load or create configlet config;if (await exists(configPath)) { const content = await readTextFile(configPath); config = JSON.parse(content);} else { config = { theme: "dark", fontSize: 14 }; await writeTextFile(configPath, JSON.stringify(config, null, 2));}
// Watch for external changesconst watcher = await watch(configPath);for await (const event of watcher) { if (event.kind === "modify") { const content = await readTextFile(configPath); config = JSON.parse(content); console.log("Config reloaded"); }}