Message Types
All messages sent over the WebSocket use a common JSON envelope defined by the Message struct. This page documents every message type, its purpose, and the JSON wire format.
Back to Home
Message Envelope
Every message shares this structure:
type Message struct {
Type MessageType `json:"type"`
Channel string `json:"channel,omitempty"`
ProcessID string `json:"processId,omitempty"`
Data any `json:"data,omitempty"`
Timestamp time.Time `json:"timestamp"`
}
The Timestamp field is set automatically by the Hub when sending. Channel and ProcessID are included only when relevant.
Type Constants
| Constant | Wire Value | Direction | Purpose |
|---|---|---|---|
TypeProcessOutput |
process_output |
Server to Client | Real-time process stdout/stderr |
TypeProcessStatus |
process_status |
Server to Client | Process lifecycle changes |
TypeEvent |
event |
Server to Client | Generic application events |
TypeError |
error |
Server to Client | Error notifications |
TypePing |
ping |
Client to Server | Keep-alive request |
TypePong |
pong |
Server to Client | Keep-alive response |
TypeSubscribe |
subscribe |
Client to Server | Subscribe to a channel |
TypeUnsubscribe |
unsubscribe |
Client to Server | Unsubscribe from a channel |
Detailed Format
process_output
Sent when a managed process produces output. Delivered only to clients subscribed to the process:{id} channel.
{
"type": "process_output",
"channel": "process:build-1",
"processId": "build-1",
"data": "Compiling main.go...",
"timestamp": "2026-02-19T10:30:00Z"
}
Server-side:
hub.SendProcessOutput("build-1", "Compiling main.go...")
process_status
Sent when a process changes state (e.g. started, exited). The data field contains a map with status and exitCode.
{
"type": "process_status",
"channel": "process:build-1",
"processId": "build-1",
"data": {
"status": "exited",
"exitCode": 0
},
"timestamp": "2026-02-19T10:30:05Z"
}
Server-side:
hub.SendProcessStatus("build-1", "exited", 0)
event
A generic event broadcast to all connected clients. The data field contains a map with event (the event name) and data (the payload).
{
"type": "event",
"data": {
"event": "user_joined",
"data": {
"user": "alice"
}
},
"timestamp": "2026-02-19T10:31:00Z"
}
Server-side:
hub.SendEvent("user_joined", map[string]string{"user": "alice"})
error
An error broadcast to all connected clients. The data field is a plain string.
{
"type": "error",
"data": "connection to database lost",
"timestamp": "2026-02-19T10:32:00Z"
}
Server-side:
hub.SendError("connection to database lost")
ping / pong
Client sends ping; the server responds with pong. Used for application-level keep-alive on top of the WebSocket protocol-level pings.
Client sends:
{
"type": "ping"
}
Server responds:
{
"type": "pong",
"timestamp": "2026-02-19T10:33:00Z"
}
Note: The server also sends WebSocket-level ping frames every 30 seconds independently of this application-level mechanism.
subscribe
Client requests subscription to a named channel. The data field is the channel name string.
{
"type": "subscribe",
"data": "process:build-1"
}
No server response is sent on success. Messages for the subscribed channel will begin arriving immediately. See Channel-Subscriptions for details.
unsubscribe
Client requests removal from a channel. The data field is the channel name string.
{
"type": "unsubscribe",
"data": "process:build-1"
}
No server response is sent. Messages for that channel will stop arriving.
Custom Messages
You can broadcast arbitrary data using the Broadcast or SendToChannel methods with a custom Message:
hub.Broadcast(ws.Message{
Type: ws.TypeEvent,
Data: map[string]any{
"event": "deployment",
"data": map[string]any{
"version": "1.2.3",
"environment": "production",
},
},
})
See Also
- Architecture -- How messages flow through the Hub
- Channel-Subscriptions -- Channel-targeted delivery
- Process-Streaming -- Process-specific message helpers