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

# WebSocket Protocol

> Raw WebSocket channels for streaming exec, PTY, file watches, lifecycle, monitor, volumes, and desktop viewer.

Nullspace exposes several WebSocket channels:

| Channel                                      | Use                                                                                  |
| -------------------------------------------- | ------------------------------------------------------------------------------------ |
| `/v1/machines/{id}/ws`                       | Streaming exec, PTY, and machine file-watch control messages.                        |
| `/v1/volumes/{id}/ws`                        | Direct volume watch events.                                                          |
| `/v1/lifecycle/ws`                           | Lifecycle event stream.                                                              |
| `/v1/monitor/ws`                             | Fleet/machine monitor stream for snapshots, updates, metrics, processes, and errors. |
| `/v1/machines/{id}/access/desktop-viewer/ws` | Managed desktop viewer bridge.                                                       |
| `machine.get_websocket_url(port)`            | Signed public WebSocket access to a service running in the machine.                  |
| `machine.get_host_info(22).websocket_url`    | Legacy signed SSH-over-WebSocket proxy URL for older port-22 fallback deployments.   |

Lifecycle and machine control channels send WebSocket Ping frames every 15
seconds and close after two missed Pong responses. PTY clients should treat a
close without `pty_exited` as a transport disconnect.

Default SSH access uses the certificate-backed relay through `nullspace ssh` and
does not consume one of these WebSocket channels.

## SDK examples

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
machine.commands.run(
    "for i in 1 2 3; do echo $i; sleep 1; done",
    shell=True,
    on_stdout=lambda data: print(data, end=""),
)
```

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
session = machine.pty.create_session()
session.send_input("pwd\n")
```

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
from nullspace import Lifecycle

lifecycle = Lifecycle()
subscription = lifecycle.subscribe(on_event=lambda event: print(event.operation))
subscription.stop()
lifecycle.close()
```

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
from nullspace import Monitor

monitor = Monitor()
subscription = monitor.subscribe(
    interval_ms=1000,
    include_processes=True,
    on_metrics=lambda event: print(event.metrics),
)
subscription.stop()
```

## Public exposed-port WebSockets

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
info = machine.get_host_info(8080)
print(info.websocket_url)
```

The signed URL is scoped to the machine, port, and WebSocket transport. Missing
or expired edge tokens fail before traffic reaches the machine service.

## Monitor subscribe message

Custom clients send a `monitor_subscribe` message to `/v1/monitor/ws`:

```json theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
{
  "type": "monitor_subscribe",
  "id": "monitor_1",
  "interval_ms": 1000,
  "include_processes": true
}
```

Server messages include `snapshot`, `update`, `metrics`, `processes`, and
`error` payloads. Use SDK callbacks unless you need a non-Python client.

## Full protocol

The longer repository protocol reference, including message shapes, lives at
`docs/product/reference/websocket-protocol.md`.

## Related

* [WebSockets guide](../networking/websockets)
* [SSH access](../access/ssh)
* [PTY sessions](../access/pty)
* [Lifecycle events](../observability/lifecycle-events)
