ctx.files stable
Host-mediated filesystem access — read, write, list, and watch files through the host rather than calling the platform directly. This is the single privileged chokepoint for the filesystem, which is why it's a core primitive — and where workspace scoping is enforced.
ctx.files: FileServiceExample
// read a file into your viewer
const text = await ctx.files.readText(path);
// write it back
await ctx.files.writeText(path, next);
// react to external changes (e.g. another tool rewrote the file)
const sub = ctx.files.watch(path, (evt) => {
if (evt.kind === "modify") reload();
});
// ...later
sub.dispose(); // stop watchingMethods
FileService (ctx.files):
| Method | What it does |
|---|---|
readText(path) | Read a file as UTF-8 text. |
readBytes(path) | Read a file's raw bytes (ArrayBuffer). |
readDir(path) | List a directory's entries as FileMeta[]. |
pathExists(path) | Resolve true if something exists at path. |
writeText(path, content) | Write UTF-8 text, creating or overwriting. |
createDir(path) | Create a directory (and missing parents). |
rename(oldPath, newPath) | Rename / move a file or directory. |
delete(path) | Delete a file or directory. |
reveal(path) | Reveal a path in the OS file manager. |
watch(path, listener) | Watch path recursively; listener gets a FileChangeEvent for changes under it. Returns a Disposable. |
Types
FileService · FileMeta · FileChangeEvent · Permission · PathDeniedError.
Workspace scoping
A third-party extension's file access is confined to the open workspace. A relative path resolves against the workspace folder ("src/index.ts" → <workspace>/src/index.ts); an absolute path is allowed only if it falls inside a workspace folder. A path outside throws PathDeniedError unless the extension declared the matching Permission — fs:read for reads, fs:write for writes — which the user consents to at install. Prefer relative paths; they're portable across machines. See the Permissions & access guide. (First-party bundled extensions are unscoped.)
Notes
Watching is host-owned: watch(path, listener) expresses intent ("tell me about changes under this path") and the host owns the underlying OS watcher(s). Each listener receives only events scoped to its path — an extension never starts or stops watchers, and never depends on another extension owning the watch.