Internal API

File Watcher

Watch directories for file system changes in real time. The watcher monitors filesystem events and streams them over the WebSocket connection at /ws.

Requires the internal server to be enabled. Up to 5 concurrent watchers per workspace.

Overview

1. Create a watcher via REST    →  get watcher ID
2. Open WebSocket at /ws        →  receive "ready" event
3. File changes in watched dir  →  receive "change" events
4. Delete watcher when done     →  cleanup

Watcher events arrive as JSON text frames on the "watcher" channel of the same WebSocket used for terminal I/O.


Create watcher

Start watching a directory for changes. The watcher recursively monitors all subdirectories and streams events over the WebSocket.

const watcher = await ws.watcher.create('ws_a1b2c3d4', {
  path: '/app/src',
  excludes: ['*.log', 'tmp'],
});

console.log(watcher.id);   // "1"
console.log(watcher.root); // "/app/src"
console.log(watcher.dirs); // 42
POST https://workspace.oblien.com/watchers
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json

{
  "path": "/app/src",
  "excludes": ["*.log", "tmp"]
}
curl -X POST "https://workspace.oblien.com/watchers" \
  -H "Authorization: Bearer $GATEWAY_JWT" \
  -H "Content-Type: application/json" \
  -d '{"path": "/app/src", "excludes": ["*.log", "tmp"]}'

Parameters

ParameterTypeRequiredDescription
pathstringYesDirectory to watch (recursively)
excludesstring[]NoGlob patterns to exclude (merged with defaults)

Response

{
  "id": "1",
  "root": "/app/src",
  "dirs": 42,
  "excludes": ["node_modules", ".git", "*.log", "tmp"]
}

Default excludes

These patterns are always excluded, even if you don't specify any:

node_modules, .git, .svn, .hg, __pycache__, .pytest_cache,
.mypy_cache, .next, .nuxt, dist, build, .DS_Store, *.swp, *.swo, *~

Your custom excludes are merged with these defaults.


List watchers

Get all active watchers.

const watchers = await ws.watcher.list('ws_a1b2c3d4');

for (const w of watchers) {
  console.log(`${w.id}: watching ${w.root} (${w.dirs} dirs)`);
}
GET https://workspace.oblien.com/watchers
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
curl "https://workspace.oblien.com/watchers" \
  -H "Authorization: Bearer $GATEWAY_JWT"

Response

{
  "watchers": [
    {
      "id": "1",
      "root": "/app/src",
      "dirs": 42,
      "excludes": ["node_modules", ".git"]
    }
  ]
}

Get watcher

Get info for a specific watcher.

GET https://workspace.oblien.com/watchers/1
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
curl "https://workspace.oblien.com/watchers/1" \
  -H "Authorization: Bearer $GATEWAY_JWT"

Response

{
  "id": "1",
  "root": "/app/src",
  "dirs": 42,
  "excludes": ["node_modules", ".git"]
}

Delete watcher

Stop a watcher and release its resources.

await ws.watcher.delete('ws_a1b2c3d4', '1');
DELETE https://workspace.oblien.com/watchers/1
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
curl -X DELETE "https://workspace.oblien.com/watchers/1" \
  -H "Authorization: Bearer $GATEWAY_JWT"

Response

{
  "success": true
}

WebSocket events

Watcher events are delivered as JSON text frames on the "watcher" channel of the /ws WebSocket. All events include the watcher_id so you can distinguish events from multiple watchers on the same connection.

ready

Sent immediately after a watcher is created and has finished scanning the directory tree.

{
  "channel": "watcher",
  "type": "ready",
  "watcher_id": "1",
  "root": "/app/src",
  "dirs": 42
}

change

Sent when a file is created, modified, deleted, or renamed within the watched directory.

{
  "channel": "watcher",
  "type": "change",
  "watcher_id": "1",
  "path": "/app/src/index.ts",
  "op": "write"
}

Operations

op valueTrigger
createFile or directory created, or moved into the watched tree
writeFile content modified or saved
removeFile or directory deleted
renameFile or directory moved out of the watched tree

Events are debounced - rapid changes to the same path within 50ms are collapsed into a single event with the last operation.

overflow

Sent when the event queue overflows. This means some events may have been lost.

{
  "channel": "watcher",
  "type": "overflow",
  "watcher_id": "1",
  "message": "Event queue overflow, some events may have been lost"
}

If you receive an overflow event, re-sync the file tree by listing the directory to get the current state.


Listening for events

Connect to the same WebSocket used for terminal I/O. Text frames with "channel": "watcher" are file watcher events.

const socket = new WebSocket('wss://workspace.oblien.com/ws', {
  headers: { Authorization: `Bearer ${gatewayJwt}` },
});

socket.onmessage = (event) => {
  if (typeof event.data === 'string') {
    const msg = JSON.parse(event.data);

    if (msg.channel === 'watcher') {
      switch (msg.type) {
        case 'ready':
          console.log(`Watcher ${msg.watcher_id} ready: ${msg.root} (${msg.dirs} dirs)`);
          break;
        case 'change':
          console.log(`${msg.op}: ${msg.path}`);
          break;
        case 'overflow':
          console.log('Events may have been lost, re-syncing...');
          break;
      }
    }
  }
};

Limits

LimitValue
Max concurrent watchers5 per workspace
Debounce interval50ms per path
Auto-watch new subdirectoriesYes
ExcludesMerged with defaults, glob matching

Error responses

StatusMeaning
400Missing or invalid path
401Missing or invalid token
404Watcher not found
409Already at 5 watchers limit
500Failed to create file watcher