Skip to main content
Deploy Nodes

Rivet Services

Self-host Durable Streams and agentOS VMs.

Rivet Services is a container of prebuilt Rivet Actors that provide services such as Durable Streams and agentOS VMs.

Run it alongside your control plane when you self-host these services. On Rivet Cloud it is already running.

Services included

Durable Streams

Real-time streams with durable history, served over HTTP at http://<host>:8642/durable-streams/v1/stream/<path>. Each stream is its own Rivet Actor, which stores the stream’s history and metadata. See Durable Streams.

agentOS

Hosted agentOS VMs, created and called through your control plane. See agentOS.

Run it

You need a running control plane and its Rivet token. See Control Plane to set one up.

Create the services node pool

curl -X PUT "http://localhost:6420/pools/services?namespace=default" \
  -H "Authorization: Bearer $RIVET_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{}'

Start Services

Docker run

docker run -d --name rivet-services \
  --add-host=host.docker.internal:host-gateway \
  -e RIVET_ENDPOINT=http://host.docker.internal:6420 \
  -e RIVET_TOKEN="$RIVET_TOKEN" \
  -e HOST=0.0.0.0 \
  -p 8642:8642 \
  rivetdev/services:0.2.5

Docker Compose

Add this service next to rivet in the Compose file from the Docker Compose guide:

  rivet-services:
    image: rivetdev/services:0.2.5
    ports:
      - "8642:8642"
    environment:
      RIVET_ENDPOINT: "http://rivet:6420"
      RIVET_TOKEN: "${RIVET_TOKEN}"
      HOST: "0.0.0.0"
    depends_on:
      - rivet
    restart: unless-stopped

Check that it works

Durable Streams

curl -X PUT -H 'content-type: application/json' \
  --data '[{"message":"hello"}]' \
  http://localhost:8642/durable-streams/v1/stream/demo

curl 'http://localhost:8642/durable-streams/v1/stream/demo?offset=-1'

The read returns [{"message":"hello"}].

agentOS

Create a VM in the services pool, then run a command in it:

VM_ID=$(curl -s -X PUT "http://localhost:6420/actors?namespace=default" \
  -H "Authorization: Bearer $RIVET_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"name":"agentOS","key":"my-vm","pool":"services","crash_policy":"sleep"}' \
  | jq -r .actor.actor_id)

curl "http://localhost:6420/gateway/$VM_ID/action/v1.process.run" \
  -H "x-rivet-token: $RIVET_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"args":[{"command":"sh","args":["-c","echo hello"],"options":{"captureStdio":true}}]}'

The response includes "stdout":"hello\n".

Configuration

VariableDescription
RIVET_ENDPOINTWhere Services reaches the control plane.
RIVET_TOKENYour Rivet token.
RIVET_NAMESPACEThe namespace to join. Defaults to default.
HOSTAddress to listen on. Set 0.0.0.0 in a container.
PORTPort to listen on. Defaults to 8642.

Local development

RivetKit starts Services automatically during local development when you run your application with its managed local control plane. Without RivetKit, npx @rivet-dev/services dev starts a local control plane and Services together.

Persistence and where data is stored

Services provides prebuilt Rivet Actors that use each Actor’s durable SQLite storage. This data is persisted by the control plane, not in the Services container. You don’t need to configure any storage for Services.

Last updated November 10, 2026