Manager HTTP API
The manager HTTP API
Editors, Ember, ash and the CLI all use the same API. The contract is docs/api/manager.openapi.yaml; a test checks that the manager serves exactly those paths.
Two modes
| Mode | Listens on | Lifetime | Tokens |
|---|---|---|---|
| ephemeral (default) | 127.0.0.1, random port | exits after --idle-timeout seconds without requests or streams (120 by default) | one token, written to managers/<pid>.json (0600) |
dedicated (--dedicated) | the host and port you set | runs until stopped | a master token and share tokens, stored hashed in manager.db |
Outside access always goes through a dedicated manager. Kernels listen on loopback only.
Authentication
Every request carries Authorization: Bearer <token>. Only the event stream and share
links also accept ?token=, because a browser EventSource cannot set headers.
GET /health needs no token.
Share tokens are bound to one kernel. A token for another kernel answers 404, not
403, so it does not reveal which kernels exist.
Paths
| Path | What |
|---|---|
GET /health | Liveness. The only path without a token. |
GET /api/manager | Mode, version, uptime and the caller's permission. |
GET /api/kernels, POST /api/kernels | List running kernels; start or attach to the kernel for a path (200 if running, 201 if started). |
GET, DELETE /api/kernels/{kernel_id} | Status; shut down. ?force=true is the only way to kill. |
POST /api/kernels/{kernel_id}/interrupt | Interrupt the running cell. |
POST /api/kernels/{kernel_id}/restart | Soft or hard restart. |
GET /api/kernels/{kernel_id}/namespace | User variables. |
GET, POST /api/kernels/{kernel_id}/runs | List run logs; start a run (mode, cells or cell_ids, params, source, on_busy). |
GET, DELETE /api/kernels/{kernel_id}/runs/{run_ref} | One run log (latest or an id); cancel a queued run. |
GET /api/kernels/{kernel_id}/runs/{run_ref}/wait | Long poll until the run ends, for clients that cannot hold a stream. |
GET /api/kernels/{kernel_id}/events | Server-Sent Events. Resume with Last-Event-ID or ?since=. |
GET /api/kernels/{kernel_id}/document, GET /api/documents | The file's cells with the latest outputs mapped on; parse any file without a kernel. |
/api/kernels/{kernel_id}/cells…, …/presence | Collaborative editing: create, edit, move, lock cells; focus and cursor. |
/api/kernels/{kernel_id}/shares… | Share tokens (dedicated manager). |
Outputs use the nbformat 4 output schema as is, so anything that reads Jupyter outputs reads these.
A running manager also serves the rendered API reference at /docs/.
An example
# Start (or attach to) the kernel for a file. 200 if it was running, 201 if started.
curl -s -X POST "$URL/api/kernels" -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"path": "/home/me/experiments/train.py"}'
# Run cells 1 and 3, queue behind a running run instead of failing with 409.
curl -s -X POST "$URL/api/kernels/$KID/runs" -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"mode": "cells", "cells": [1, 3], "params": {"lr": 0.02}, "on_busy": "queue"}'
# Follow events. EventSource cannot set headers, so SSE also accepts ?token=.
curl -N "$URL/api/kernels/$KID/events?token=$TOKEN"
# Stop means interrupt.
curl -s -X POST "$URL/api/kernels/$KID/interrupt" -H "Authorization: Bearer $TOKEN"
A second run while the kernel is busy answers 409 with the current run, unless the request
sets "on_busy": "queue".
Events
GET /api/kernels/{kernel_id}/events is a Server-Sent Events stream: run started and finished,
cell started and finished, outputs, and document changes. The SSE id is the kernel's event
sequence number. A client that reconnects with Last-Event-ID gets what it missed while the
kernel's replay buffer still has it.
No versions
Paths have no version segment (INTENT D16). The API only grows: fields, optional request fields, paths and
error codes are added, never renamed or removed. A replaced field stays, marked deprecated.
Clients ignore fields they do not know.
What is changing
Long-lived streams (events, the run-wait long poll) will be handed by the manager to the kernel as a socket, so they keep flowing when the manager exits changing #47. The 2025 authentication is being restored: one password and one master token per manager under /api/auth, and access tokens that the kernel itself holds, so they work through any manager changing #48. Permissions become a set of five capabilities (read, history, execute, edit, manage) instead of viewer tiers, and collaboration moves to the 2025 WebSocket sync changing #49. Managers and kernels will admit only the same OS account changing #55. Short REST calls such as runs and interrupt keep their shape.