Overview
The Node client is a CLI wrapper around MCP-over-WebSocket to VAGUS relay. It supports pair/connect, read/call/list operations, and long-running subscriptions with JSONL output.
Entry: scripts/vagus-connect.js
Manager: scripts/vagus-manager.js
Session file: ~/.openclaw/vagus-session.json
Transport: wss://relay.withvagus.com/connect/<token>
Related: Server (Android App) for MCP surface and governance, Self-Hosted Relay for infrastructure setup.
Setup
cd ~/.openclaw/skills/vagus/scripts
npm install
node vagus-connect.js pair <PAIR_CODE>
node vagus-connect.js status
CLI Commands
node {baseDir}/scripts/vagus-connect.js <command> [args]
| Command | Args | Description |
|---|---|---|
pair | <code> | Pair and persist session token. |
connect | none | Connect using saved session. |
status | none | Get connectivity and active modules. |
read | <uri> | One-shot resource read. |
subscribe | <uri> | Long-running JSONL stream with lifecycle, stream_state, and update events. |
unsubscribe | <uri> | Stop a resource subscription. |
call | <tool> '<json>' | Invoke a tool call. |
list-resources | none | List available resource URIs. |
list-tools | none | List available tools + schemas. |
disconnect | none | Delete local session file. |
vagus-manager.js add | <uri> | Add a URI to the managed persistent subscription set. |
vagus-manager.js remove | <uri> | Remove a URI from the managed persistent subscription set. |
vagus-manager.js list | none | List active managed subscriptions. |
vagus-manager.js status | none | Read managed stream freshness state and lifecycle status. |
JSONL Contract
All outputs are line-delimited JSON objects.
{"type":"paired","session_token":"..."}
{"type":"capabilities","resources":["..."],"tools":["..."]}
{"type":"resource","uri":"vagus://device/screen","data":{"screen_on":true,"locked":false}}
{"type":"stream_state","uri":"vagus://device/screen","status":"fresh","freshness_ms":132,"thresholds":{"observed_p95_interval_ms":1000,"delayed_after_ms":2500,"stale_after_ms":6000,"unavailable_after_ms":20000}}
{"type":"result","tool":"notify","success":true,"data":{"content":[{"type":"text","text":"{\"ok\":true}"}]}}
Request Metadata and Trace IDs
MCP response and notification envelopes include a top-level trace_id field when available. This identifier provides end-to-end correlation across request handling, outbound notifications, and server audit logs.
{
"jsonrpc": "2.0",
"id": 3,
"trace_id": "43818824:tools/call:5545a8fa214dd67e:405164970b59034e",
"result": {
"content": [ { "type": "text", "text": "{\"ok\":true,\"id\":9098}" } ],
"isError": false
}
}
{
"jsonrpc": "2.0",
"method": "notifications/resources/updated",
"trace_id": "43818824:resources/subscribe:5545a8fa214dd67e:aa3d70c94091b898",
"params": {
"sessionId": "5545a8fa214dd67e",
"uri": "vagus://device/screen",
"data": { "screen_on": true, "locked": false, "ts": 1772043993616 },
"ts": 1772043993632
}
}
The vagus-connect.js wrapper emits normalized JSONL and preserves MCP correlation context (including trace_id) in the mcp object for operational commands (read/call/list/subscribe/unsubscribe and streamed updates).
If you need the full raw JSON-RPC envelope, capture raw MCP frames in custom integrations.
Managed Streaming
For persistent field operation, prefer vagus-manager.js over multiple independent subscribe
processes. The manager keeps one MCP session alive, auto-reconnects, re-subscribes active URIs, and tracks
adaptive freshness per stream.
node {baseDir}/scripts/vagus-manager.js
node {baseDir}/scripts/vagus-manager.js add vagus://sensors/location
node {baseDir}/scripts/vagus-manager.js remove vagus://inference/attention
node {baseDir}/scripts/vagus-manager.js list
node {baseDir}/scripts/vagus-manager.js status
Stale detection is dynamic: thresholds are learned from observed inter-arrival timing only. The manager does not assume a hard-coded cadence per resource.
Resources
vagus://session/infovagus://sensors/motion,activity,activity_recognition,location,environmentvagus://inference/attention,indoor_confidence,sleep_likelihood,notification_timingvagus://device/connectivity,screen,battery,clipboard,notificationsvagus://io/type_*dynamic onboard sensor resources (device-specific)
node {baseDir}/scripts/vagus-connect.js read vagus://session/info
node {baseDir}/scripts/vagus-connect.js subscribe vagus://device/screen
Subscriptions vs Read-Only
Before using subscribe, confirm the URI supports streaming semantics on the server.
| URI | read |
subscribe |
Node-Client Behavior |
|---|---|---|---|
vagus://session/info | Supported | Supported | Use subscribe for ongoing runtime/session telemetry. |
vagus://sensors/motion | Supported | Supported | High-frequency stream; subscribe for continuous updates. |
vagus://sensors/location | Supported | Supported | Event-driven location updates during movement. |
vagus://device/connectivity | Supported | Supported | Event-driven connectivity state changes. |
vagus://device/clipboard | Supported | Not supported | Use read only; subscribe returns MCP invalid request. |
vagus://device/screen | Supported | Supported | Event-driven updates when screen state changes. |
vagus://device/notifications | Supported | Supported | Event-driven updates when notifications post/remove. |
vagus://device/battery | Supported | Supported | Low-frequency updates (~5 minutes) in subscription mode. |
vagus://sensors/activity, activity_recognition, environment, vagus://inference/* | Supported | Supported | Cadence controlled by Infer resolution in app UI. |
vagus://io/type_* | Supported | Supported | Cadence controlled by I/O resolution in app UI. |
Tools
| Tool | Required Params | Constraints / Governance |
|---|---|---|
notify | title, body | title/body max 200/1000; requires notifications capability enabled. |
speak | text | text max 5000; optional voice/language/rate/pitch/interrupt values validated server-side. |
sms/send | to, body | body max 2000; Android SEND_SMS and SMS governance policy must allow. |
intent/open_url | url | URL must be http/https; policy may enforce HTTPS-only. |
calendar/create_event | title | Optional start/end/location/description/allDay fields; calendar permissions and policy apply. |
clipboard/set | content | content max 10000; blocked when clipboard capability is disabled. |
haptic/pulse | none | Optional durationMs (10-5000, default 120); requires haptics capability and Android vibrate permission. |
haptic/pattern | none | Optional pattern integer array; requires haptics capability and Android vibrate permission. |
agent/set_name | name | Max 64 chars; empty string clears the stored name. |
io/set_subscription_resolution | resolutionMs | Allowed values: 1500, 10000, 30000, 60000, 90000, 120000, 300000; requires Allow agent to set resolution. |
infer/set_subscription_resolution | resolutionMs | Allowed values: 1500, 10000, 30000, 60000, 90000, 120000, 300000; requires Allow agent to set infer resolution. |
node {baseDir}/scripts/vagus-connect.js call sms/send '{"to":"+14388090319","body":"Test message"}'
node {baseDir}/scripts/vagus-connect.js call intent/open_url '{"url":"https://withvagus.com"}'
node {baseDir}/scripts/vagus-connect.js call io/set_subscription_resolution '{"resolutionMs":30000}'
node {baseDir}/scripts/vagus-connect.js call infer/set_subscription_resolution '{"resolutionMs":30000}'
node {baseDir}/scripts/vagus-connect.js call calendar/create_event '{"title":"dayclub","startTimeMs":1771772400000,"endTimeMs":1771776000000,"allDay":false}'
io/set_subscription_resolution controls cadence for all vagus://io/type_*
subscriptions and is gated by the device-side toggle Allow agent to set resolution (default off).
infer/set_subscription_resolution controls infer cadence and is gated by
Allow agent to set infer resolution (default off).
User Permissions (Server-Side)
Permissions are enforced in the VAGUS Android app. The Node client can issue MCP reads and tool calls, but execution is gated by user-configured capability toggles and runtime approval prompts.
| Permission Layer | Owner | Node Client Impact |
|---|---|---|
| Module/capability enablement | User in VAGUS app settings | Unavailable capabilities fail at read/call time. |
| Runtime approval prompts | User on device | Sensitive tool calls may be approved, denied, or timeout. |
| Agent identity context | agent/set_name + app context | Shown in approval/governance context. |
Expected automation behavior: on permission denial/timeout, return a clear user action ("approve in VAGUS" or "enable permission"), then retry once.
Timeouts and Liveness
| Setting | Value |
|---|---|
| MCP request timeout | 22000ms |
| MCP initialize timeout | 20000ms |
| WS heartbeat interval | 30000ms |
| Pong timeout | 10000ms |
Error Codes
| Code | Meaning |
|---|---|
NO_COMMAND | No subcommand passed. |
NO_SESSION | No saved session file. |
PAIR_FAILED | Pairing API failed. |
SESSION_EXPIRED | Token rejected by relay. |
CONNECT_FAILED | WSS connect/init failure. |
BAD_JSON | Invalid tool arg JSON. |
READ_FAILED | Resource read failed. |
CALL_FAILED | Tool invocation failed or timed out. |
FATAL | Unhandled client error. |