Terminal
The terminal endpoints let you create interactive PTY sessions inside the workspace VM. Terminal I/O is multiplexed over a single WebSocket connection.
Requires the internal server to be enabled. Up to 10 concurrent terminal sessions per workspace.
Overview
1. Create a terminal session → get session ID
2. Open WebSocket at /ws → bidirectional I/O
3. Send stdin as binary → [id_byte][data]
4. Receive stdout as binary → [id_byte][data]
5. Resize / close via JSON messages or RESTCreate session
Create a new terminal session with an interactive PTY.
const term = await ws.terminal.create('ws_a1b2c3d4', {
shell: '/bin/bash',
cols: 120,
rows: 40,
});
console.log(term.id); // "1"
console.log(term.cols); // 120
console.log(term.rows); // 40POST https://workspace.oblien.com/terminals
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
{
"cmd": ["/bin/bash"],
"cols": 120,
"rows": 40
}curl -X POST "https://workspace.oblien.com/terminals" \
-H "Authorization: Bearer $GATEWAY_JWT" \
-H "Content-Type: application/json" \
-d '{"cmd":["/bin/bash"],"cols":120,"rows":40}'Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
cmd | string[] | No | Command to run (e.g. ["/bin/bash"]). Falls back to default shell |
command | string[] | No | Alias for cmd |
cols | integer | No | Terminal width in columns |
rows | integer | No | Terminal height in rows |
Response
{
"success": true,
"id": "1",
"cols": 120,
"rows": 40,
"command": ["/bin/bash"]
}HTTP status: 201 Created
List sessions
List all active terminal sessions.
const sessions = await ws.terminal.list('ws_a1b2c3d4');
for (const term of sessions.terminals) {
console.log(`${term.id}: ${term.command.join(' ')} (alive: ${term.alive})`);
}GET https://workspace.oblien.com/terminals
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...curl "https://workspace.oblien.com/terminals" \
-H "Authorization: Bearer $GATEWAY_JWT"Response
{
"success": true,
"terminals": [
{
"id": "1",
"command": ["/bin/bash"],
"cols": 120,
"rows": 40,
"alive": true,
"exit_code": 0,
"created_at": "2025-01-15T10:30:00Z"
}
]
}Close session
Close a terminal session and kill its process.
await ws.terminal.close('ws_a1b2c3d4', '1');DELETE https://workspace.oblien.com/terminals/1
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...curl -X DELETE "https://workspace.oblien.com/terminals/1" \
-H "Authorization: Bearer $GATEWAY_JWT"Response
{
"success": true,
"terminal_id": "1"
}Get scrollback
Retrieve the scrollback buffer for a terminal session. Useful for restoring terminal state after reconnection.
const scrollback = await ws.terminal.scrollback('ws_a1b2c3d4', '1');
console.log(scrollback.size); // bytes in buffer
console.log(scrollback.alive); // session still running
console.log(scrollback.scrollback); // base64-encoded dataGET https://workspace.oblien.com/terminals/1/scrollback
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...curl "https://workspace.oblien.com/terminals/1/scrollback" \
-H "Authorization: Bearer $GATEWAY_JWT"Response
{
"success": true,
"scrollback": "dXNlckBzYW5kYm94Oi9hcHAkIA==",
"size": 2048,
"alive": true,
"exit_code": 0
}| Field | Description |
|---|---|
scrollback | Base64-encoded terminal output (64 KiB ring buffer) |
size | Size of the scrollback data in bytes |
alive | Whether the session is still running |
exit_code | Process exit code (0 if still alive) |
WebSocket
Terminal I/O flows over a single multiplexed WebSocket connection at /ws. Multiple terminal sessions share the same connection.
Connect
// Auto-connect when using terminal manager
const term = await ws.terminal.create('ws_a1b2c3d4', { shell: '/bin/bash' });
term.on('data', (data) => process.stdout.write(data));
term.on('exit', (code) => console.log(`Exited: ${code}`));
term.write('ls -la\n');
term.resize(160, 50);WebSocket: wss://workspace.oblien.com/ws
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...const ws = new WebSocket('wss://workspace.oblien.com/ws', {
headers: { Authorization: `Bearer ${gatewayJwt}` },
});
ws.binaryType = 'arraybuffer';
ws.onmessage = (event) => {
if (event.data instanceof ArrayBuffer) {
// Binary: terminal output
const bytes = new Uint8Array(event.data);
const terminalId = bytes[0];
const data = bytes.slice(1);
console.log(`Terminal ${terminalId}:`, new TextDecoder().decode(data));
} else {
// Text: control messages (exit, etc.)
const msg = JSON.parse(event.data);
console.log('Control:', msg);
}
};Protocol
Binary frames
| Direction | Format | Description |
|---|---|---|
| Client → Server | [id_byte][stdin_data] | Send input to terminal |
| Server → Client | [id_byte][stdout_data] | Receive output from terminal |
The first byte is the terminal ID byte (mapped from the session ID). The remaining bytes are raw terminal data.
Text frames
Resize a terminal:
{
"channel": "terminal",
"type": "resize",
"id": "1",
"cols": 160,
"rows": 50
}Terminal exit notification (server → client):
{
"channel": "terminal",
"type": "exit",
"id": "1",
"code": 0
}On connect
When a WebSocket connection is established, the server automatically sends:
- Scrollback data - binary frames with buffered output for each active session
- Exit notifications - text frames for any sessions that have already exited
This allows clients to restore terminal state after reconnection without explicit scrollback requests.
Error responses
| Status | Meaning |
|---|---|
400 | Missing terminal ID |
401 | Missing or invalid token |
404 | Terminal session not found |
405 | Method not allowed |
500 | Failed to create PTY session |