Synced from Hive. This page is pulled from hivecommons/hive@v5 during the docs build. Edit the canonical source in the Hive repository.

Dashboard REST API reference — Sessions

Part of the Dashboard REST API reference; see that page for how auth levels and pkg/<file>:<line> source citations are read and checked. Edit this file for routes in this area and run src/scripts/check-api-reference-citations.sh --fix to resync citations.

Sessions are interactive, named CLI-agent terminals. Each runs as its own unprivileged uid and is private to its creator and the hive owners unless shared is set (see security model). The feature is off unless dashboard.sessions.enabled (or HIVE_SESSIONS_ENABLED) is true; while off, GET /api/sessions answers {"enabled":false,"sessions":[],"vendors":[],"limits":{}} and every other route answers 404. Errors are {"ok":false,"error":"..."}.

MethodPathAuthPurposeSource
GET/api/sessionsDashboard auth/sessionSessions, vendors and limitspkg/dashboard/api_sessions.go:156
POST/api/sessionsOwner or read-writeCreate a session {name, group, vendor, shared?}; answers 202 at once with the session preparing, the start runs in the backgroundpkg/dashboard/api_sessions.go:157
PATCH/api/sessions/{id}Session creator or ownerRename, regroup or (un)share {name?, group?, shared?}pkg/dashboard/api_sessions.go:158
DELETE/api/sessions/{id}Session creator or ownerClose a running session (metadata kept, marked ended); on an ended session, remove its metadata and delete its sandbox filespkg/dashboard/api_sessions.go:159
GET/api/sessions/{id}/logDashboard auth/sessionRedacted scrollback ?lines=N (capped at 5000)pkg/dashboard/api_sessions.go:160
POST/api/sessions/{id}/inputOwner or read-writeQueue {text, submit} for the pane; answers 202 with {queued: {id, position}, queue} and the text is typed once the CLI prompt is idle (size-capped, audited at delivery without the text)pkg/dashboard/api_sessions.go:161
DELETE/api/sessions/{id}/input/{queue_id}Owner or read-writeCancel your own queued send (the creator or an owner may cancel anyone’s); 409 while it is being deliveredpkg/dashboard/api_sessions.go:165
POST/api/sessions/{id}/uploadOwner or read-writeMultipart file; returns the absolute path inside the session directorypkg/dashboard/api_sessions.go:162
POST/api/sessions/{id}/resumeOwner or read-writeReopen an ended session’s last conversation where the vendor supports it (409 otherwise); answers 202 with the session preparingpkg/dashboard/api_sessions.go:163
POST/api/sessions/{id}/keyboardOwner or read-write{"action":"take"|"release"} the keyboard lease: the one writable terminalpkg/dashboard/api_sessions.go:164

Session object

{id, name, group, vendor, creator, created_at, last_activity, status, attached, tmux_name, resumable, shared, workspace_repo, workspace, message, error, keyboard_holder, keyboard_since, keyboard_mine, viewers, queue} where status is preparing, running, failed or ended, attached is the number of live attached tmux clients (each list probe detaches clients whose process is gone or no longer descends from the terminal attacher, so a stale client never counts) and tmux_name is hive-sess-<id>. resumable, shared, workspace_repo, workspace, message, error and the keyboard, presence and queue fields are additive. keyboard_holder is the user whose terminal is writable ("" when released), keyboard_since when they took it and keyboard_mine whether that is the caller. viewers is [{user, attached_since, keyboard}], one entry per person with a live terminal on the session (several tabs collapse into one). queue is {length, head, position, items: [{id, user, bytes, submit, queued_at, delivering, mine}]}: the pending sends, never their text, with position the caller’s own first item (0 when none). GET /api/sessions lists only sessions the caller created, owners (all) and shared sessions; the log, input, upload, resume, keyboard and terminal routes answer 404 for a session the caller cannot see and 403 when it is visible but not usable.

Roles

RoleList, log, watch the live terminalSend (/input), upload, keyboardRename, share, close, resume, delete
read (shared session only)yes, read-onlynono
read-write (creator, or any writer on a shared session)yesyescreator only
owneryesyesyes

A private session is visible only to its creator and owners, whatever the role. The read role never types: its terminal attach is read-only and /input, /upload and /keyboard answer 403.

Lifecycle

A create (or resume) never blocks the request on the start. The record is saved and answered as preparing with a human message (preparing workspace: cloning org/repo (first session on this hive) when the workspace does not exist yet, otherwise the vendor being started), and the start runs in the background: the one-time clone of the workspace, its hand-over to the sessions group, spektacular init and the tmux server. Poll GET /api/sessions until the session is running (the terminal can then be attached) or failed, in which case error carries the reason (tokens redacted) and DELETE removes the record; a resume whose start fails goes back to ended with error set and stays resumable. Preparing sessions count against the limits, answer 409 to input, upload, terminal handoff and DELETE, and a second create that needs the same workspace waits for the clone in flight instead of starting another. A preparing record found after a hive restart, with no start behind it, is marked failed on the next list. The create is audited as session_created and its outcome as session_started (outcome=running or outcome=failed with the error).

Workspace

Every session’s CLI starts inside the hive’s session workspace: one persistent clone per repository, <HIVE_SESSIONS_WORKSPACE_DIR>/<org>/<repo> (default /data/session-sandbox/workspace/...), shared by every session on the hive the way one checkout is shared by several people at one machine (two sessions editing the same file see each other’s edits; git fetch is never run for you). The repository is dashboard.sessions.workspace_repo (HIVE_SESSIONS_WORKSPACE_REPO), defaulting to the hive’s own project.org/primary_repo; with neither set, a session opens in its own empty directory. The hive clones once, with a short-lived App token in a one-shot credential helper that is deleted afterwards, so the clone’s config and origin carry no credential: pushing from a session uses the person’s own login. On every start the hive runs spektacular init <vendor> in the workspace once per vendor spek supports (claude, bob, codex, copilot, omp) when /usr/local/bin/spektacular (runs.spektacular.binary) is installed; a missing binary or a failed init is logged and the session still starts. GET /api/sessions reports the configured workspace as workspace: {repo, path}; each session carries the workspace_repo and workspace it was created in and a resume reopens that one. Uploads stay under the session’s own directory (/upload returns their path).

Attaching a terminal

POST /api/terminal/handoff accepts an optional body {"session":"<id>"}. The response is unchanged ({code, expires_in}); the UI then opens /terminal/?arg=hive-sess-<id>&code=<code>. The code is bound to that session id and caller, opens only ?arg=hive-sess-<id>, and is refused (503) when the hive has no ttyd attach key. Anyone who can see the session may attach (the read role included, on a shared session); an agent-terminal code still needs owner or read-write.

Keyboard lease. Exactly one person at a time holds a session’s keyboard; everyone else is attached read-only (tmux attach-session -r). The creator holds it from the start and whoever resumes an ended session takes it. The dashboard decides the mode of every attach: it appends the per-session attach token as ttyd’s second arg and, for the holder only, a second write token (HMAC-SHA256(HIVE_TTYD_ATTACH_KEY, "hive-ttyd-attach-rw-v1\0hive-sess-<id>")) as the third; ttyd-tmux.sh verifies both and attaches read-only when the write token is missing or wrong. The browser sends one arg (the session name), so nothing it adds can make an attach writable. POST /api/sessions/{id}/keyboard with {"action":"take"}: owners and the creator always get it; another read-write user gets it only when it is released or the holder has been idle (not attached, or no pane activity since the later of the hand-over and the last activity) for HIVE_SESSIONS_KEYBOARD_GRACE_SEC (default 60), otherwise 409 {holder, grace_seconds}. {"action":"release"} is for the holder, the creator or an owner. A hand-over detaches the previous holder’s writable tmux client at once; both browsers re-attach with a fresh handoff in their new mode. Every hand-over is audited as session_keyboard with from and to, so keystrokes typed in the terminal are attributable to the holder of record at that time.

Presence. viewers in the session object is the set of live terminal websockets per user, with keyboard true for the holder.

Queued Send

POST /api/sessions/{id}/input validates the text (UTF-8, no control characters but tab and newline) and queues it: 202 with {queued: {id, position}, queue}. One worker per session delivers the head only when the pane is idle, waits for idle again, then delivers the next. Idle means: none of the vendor’s busy markers or a spinner glyph (⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏) in the last 12 lines, and, among the last 4 non-decoration lines (box-drawing stripped), a line that is exactly the prompt prefix with nothing typed after it:

VendorEmpty prompt lineBusy markers (case-insensitive)
claude› or >esc to interrupt, to interrupt
copilot> or ›esc to interrupt, to interrupt, to cancel
codex› or >esc to interrupt, to interrupt, working
any other›, > or ❯to interrupt

A permission prompt, a half-typed line or a run in progress therefore holds the queue. The heuristic fails open: an item that has waited HIVE_SESSIONS_SEND_WAIT_SEC (default 45) is delivered anyway, so a send is never stuck. The queue holds at most 32 items (429 beyond); it is dropped when the session ends. DELETE /api/sessions/{id}/input/{queue_id} cancels your own item (the creator or an owner may cancel anyone’s), 409 once it is being delivered. Each delivery is audited as session_input with the user who queued it, the byte count, submit and queued_sec, never the text; session_upload is audited at upload time as before.

Limits

limits in GET /api/sessions reports max_sessions, max_per_user, idle_ttl_hours, max_input_bytes, max_upload_bytes and max_uploads_per_session. Defaults are 12, 4, 72 hours, 64 KiB, 10 MiB and 25; each is overridable (HIVE_SESSIONS_MAX, HIVE_SESSIONS_MAX_PER_USER, HIVE_SESSIONS_IDLE_TTL_HOURS, HIVE_SESSIONS_MAX_INPUT_BYTES, HIVE_SESSIONS_MAX_UPLOAD_BYTES, HIVE_SESSIONS_MAX_UPLOADS).