# How to watch files for changes in a sandbox Call `sbx.files.watch(dir, onEvent, { recursive: true })`; it reports each create, write, remove, rename and chmod as it happens. **On Runtime a file watch survives a pause and loses nothing.** Reading a watch never wakes a paused sandbox: delivery stops, and after the wake the watch carries on from the same place. It does what E2B's `watchDir` does and adds include and exclude globs, batching and overflow notices. A paused sandbox costs $0.08 per decimal GB of saved state a month and no compute ([pricing](/docs/pricing#paused-storage), checked 25 September 2026). ## Watch a directory ```ts check import { Sandbox } from "withruntime"; await using sbx = await Sandbox.create(); const watch = await sbx.files.watch("/workspace", (event) => console.log(event.type, event.path), { recursive: true, exclude: ["node_modules", ".git/**"], onNotice: (notice) => console.warn("rescan:", notice), onExit: (reason) => console.log("watch ended:", reason), }); await sbx.exec("echo hi > /workspace/note.txt"); await watch.stop(); ``` ```python check from withruntime import Sandbox with Sandbox.create() as sbx: watch = sbx.files.watch("/workspace", recursive=True, exclude=["node_modules", ".git/**"]) sbx.exec("echo hi > /workspace/note.txt") for event in watch.get_new_events(wait_ms=2000): print(event["type"], event["path"]) print(watch.notices) watch.stop() ``` In Python, `get_new_events(wait_ms=...)` returns what has arrived and `watch.events()` iterates until the watch ends. A rename event carries the old path as well. From a terminal, `watch` prints each change until Ctrl-C: ```bash no-run runtime sandbox watch "${id}" /workspace --recursive --exclude node_modules --exclude '.git/**' runtime sandbox watch "${id}" /workspace/src --events create,write --include '**/*.py' ``` An agent over MCP uses `runtime_sandbox_files_watch` to start a watch, read its events after a cursor, list watches and stop one ([MCP](/docs/mcp)). ## After a pause A watch stops delivering when its sandbox pauses and resumes where it stopped: ```ts check import { Sandbox } from "withruntime"; const sbx = await Sandbox.create({ idlePauseSeconds: 600 }); const watch = await sbx.files.watch("/workspace/src", (e) => console.log(e.type, e.path), { recursive: true, onExit: async (reason) => { if (reason === "paused") { await sbx.wake(); watch.resume(); // nothing lost } }, }); ``` In Python, `events()` stops with `exit_reason == "paused"`, and calling it again after the wake carries on from the same place. ## Options and limits | Option or limit | Value | | -------------------- | ---------------------------------------------------------------------------------- | | Events | `create`, `write`, `remove`, `rename` (with the old path), `chmod` | | `recursive` | Watch subdirectories; a new directory is scanned as it appears | | `include`, `exclude` | Globs; an excluded directory is not watched at all | | `events` | Only these kinds, such as `create,write` on the CLI | | Batching | Repeated writes to one file in a batch come as one event with a `count` | | Watches per sandbox | At most four | | `timeoutMs` | One hour by default, then the watch ends | | Flood cap | 5,000 events a second; the rest reported as an `overflow` notice, never silently | | Over HTTP | `POST /v1/sandboxes/{id}/files/watches`; events after a `cursor`, `waitMs` to 8000 | | Cost | No charge per watch; the sandbox's measured CPU and reserved memory | ## Mistakes to avoid - **Watching `node_modules` or `.git`.** They change in bursts of thousands of files. Exclude them: an excluded directory is not watched at all, so its churn never reaches the watch. - **Assuming a quiet watch means no changes.** After a flood past 5,000 events a second the watch sends an `overflow` notice through `onNotice` (or `watch.notices` in Python) with how many were dropped. Rescan the directory when you see one. - **A fifth watch.** A sandbox runs four at most. Watch a common parent with `recursive` and filter with `include`, rather than one watch per folder. - **Treating `onExit("paused")` as the end.** It means the sandbox paused. Call `watch.resume()` once it wakes and the stream continues. - **Leaving it to time out silently.** A watch ends after `timeoutMs`, an hour by default. Handle `onExit` and start a new one if you still need it. ## Where this helps - A coding agent edits files while your UI shows each change live, as in [Claude Code in a sandbox](/integrations/claude-code). - A dev server's source folder is watched to rebuild or reload a [preview](/use-cases/preview-agent-built-apps). - A grader collects each file a student's program writes ([grade student code](/use-cases/grade-student-code)). The SDK reference is at [watch files](/docs/javascript#watch-files). Facts on this page were checked on 25 September 2026.