Skip to main content
PTY sessions run over the sandbox WebSocket channel and also expose REST helpers for listing, resizing, and killing sessions. Idle PTY streams remain connected while the sandbox is running. A WebSocket close without a pty_exited message is reported as a transport disconnect. Session IDs are scoped to the current running sandbox execution; after hibernate/resume, create a new PTY session.

Create a session

session = sandbox.pty.create_session(cols=100, rows=30, cwd="/workspace")
chunks = []

session.send_input("pwd\nexit\n")
session.wait(on_data=lambda chunk: chunks.append(chunk.decode("utf-8")), timeout=5)
print("".join(chunks))

Disconnect and reconnect

session_id = session.session_id
session.disconnect()

reattached = sandbox.pty.connect(
    session_id=session_id,
    on_data=lambda chunk: print(chunk.decode("utf-8"), end=""),
)
reattached.send_input("echo reattached\n")
Use the session_id printed by sandbox pty create with --session-id. Numeric pid reconnect remains available for legacy scripts. In a local TTY, connect forwards keyboard input, streams PTY output, and tracks terminal resize events. With --json, it waits for completion, forwards piped stdin when present, and prints the final result. PTY session IDs and legacy PIDs are not durable across hibernate/resume.

Manage sessions

sessions = sandbox.pty.list_sessions()
session_id = sessions[0].session_id
sandbox.pty.resize_session(session_id, 140, 40)
sandbox.pty.kill_session(session_id)
The session handle exposes id, session_id, pid, is_connected, exit_code, and error. It also supports byte iteration when you want to read PTY output directly:
for chunk in session:
    print(chunk.decode("utf-8"), end="")
Use session.resize(cols, rows) for the active WebSocket handle. Use resize_session(session_id, cols, rows) when you are managing a session by ID.