> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gravixlayer.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Watch Directory

> Stream filesystem change notifications from a runtime directory

`GET /v1/agents/runtime/{runtime_id}/files/watch`

Streams filesystem change notifications as Server-Sent Events. The watch is backed by the
guest kernel's `inotify` interface, so events are delivered as the kernel observes them
rather than by polling: there is no scan interval and no CPU cost while the tree is idle.

Use this to react to a build writing artefacts, an agent editing source files, or a long
running job dropping results into a directory.

<CodeGroup>
  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  from gravixlayer import GravixLayer

  client = GravixLayer()  # defaults to cloud="aws", region="us-east-1"
  sandbox = client.runtime.create()  # defaults to template="base-small"
  sandbox.file.create_directory("/workspace/out")

  for event in sandbox.file.watch("/workspace/out", recursive=True):
      if event.type == "start":
          print("watch armed")
          sandbox.file.write("/workspace/out/done.txt", "ok\n")
          continue
      print(event.type, event.path, event.new_path)
      if event.name == "done.txt":
          break

  sandbox.kill()
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import { GravixLayer } from 'gravixlayer';

  const client = new GravixLayer(); // defaults to cloud="aws", region="us-east-1"
  const sandbox = await client.runtime.create(); // defaults to template="base-small"
  await sandbox.file.createDirectory('/workspace/out');

  for await (const event of sandbox.file.watch('/workspace/out', { recursive: true })) {
    if (event.type === 'start') {
      console.log('watch armed');
      await sandbox.file.write('/workspace/out/done.txt', 'ok\n');
      continue;
    }
    console.log(event.type, event.path, event.newPath);
    if (event.name === 'done.txt') break;
  }

  await sandbox.kill();
  ```

  ```bash CLI theme={"theme":{"light":"github-light","dark":"github-dark"}}
  gravixlayer runtime files watch "$RT" /workspace/out --recursive
  ```

  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -N "https://api.gravixlayer.ai/v1/agents/runtime/$RT/files/watch?path=/workspace/out&recursive=true" \
    -H "Authorization: Bearer $GRAVIXLAYER_API_KEY"
  ```
</CodeGroup>

## Parameters

| Parameter   | Type    | Required | Description                                                                  |
| ----------- | ------- | -------- | ---------------------------------------------------------------------------- |
| `path`      | string  | Yes      | Directory to watch                                                           |
| `recursive` | boolean | No       | Also watch subdirectories, including ones created later. Defaults to `false` |

## Events

Each SSE frame carries one JSON object.

| Field        | Type    | Description                                               |
| ------------ | ------- | --------------------------------------------------------- |
| `type`       | string  | `start`, `create`, `write`, `remove`, `rename` or `chmod` |
| `name`       | string  | Base name of the affected entry                           |
| `path`       | string  | Absolute path of the affected entry                       |
| `new_path`   | string  | Destination path, populated only for `rename`             |
| `watcher_id` | string  | Identifier of the underlying guest watcher                |
| `timestamp`  | integer | Event time in Unix nanoseconds                            |

The first event is always `start`. It confirms the watch is armed; only changes that occur
after `start` are guaranteed to be observed. Arm the watch before triggering the work you
want to observe.

```
data: {"type":"start","watcher_id":"w-3f1a","path":"/workspace/out"}

data: {"type":"create","name":"part-0.json","path":"/workspace/out/part-0.json","timestamp":1760000000123456789}

data: {"type":"write","name":"part-0.json","path":"/workspace/out/part-0.json","timestamp":1760000000987654321}

data: {"type":"rename","name":"part-0.json","path":"/workspace/out/part-0.json","new_path":"/workspace/out/final.json","timestamp":1760000001000000000}
```

## Behaviour notes

* **Writes are coalesced.** A burst of writes to the same file within a short window is
  reported as a single `write`, so a large file copy does not produce thousands of events.
* **Renames are paired.** A move within the watched tree is reported once as `rename` with
  both `path` and `new_path`, not as a separate `remove` and `create`.
* **The stream is open ended.** Iterate for as long as you want notifications and break out
  to stop watching; the underlying HTTP response and the guest watcher are released when
  you do.
* **Recursive watches cover new subdirectories.** Directories created after the watch is
  armed are picked up automatically.
