Code cells
A code cell runs real code against a real Jupyter kernel, Python, JavaScript, or anything else with an installed kernelspec, directly from a bullet. Subspace speaks the Jupyter wire protocol itself: there is no Python of ours, no jupyter-server process to run, and no notebook file format to reconcile. The kernel is just another process the server spawns and talks to.
Creating a cell
Section titled “Creating a cell”Type a backtick (`) at the start of a bullet’s text and the bullet converts into a
code cell. The node’s text becomes the cell’s source, edited in a
CodeMirror 6 editor with syntax highlighting for the
kernelspec’s language, Python, JavaScript, or TypeScript get full highlighting; anything
else falls back to plain text.
Picking a kernel
Section titled “Picking a kernel”Each cell has its own kernel picker in the node-frame header. It lists every kernelspec
Subspace discovers on the standard Jupyter search paths (~/Library/Jupyter/kernels,
/usr/local/share/jupyter/kernels, and any directories in $JUPYTER_PATH), so any kernel
you’d normally see in Jupyter or JupyterLab shows up here with no extra configuration.
Picking a kernel spawns it (or reuses an already-running instance for that cell) the
first time you execute.
Executing a cell
Section titled “Executing a cell”⌘↵ (or the execute button in the frame header) runs the cell, following the
universal activation convention every element shares. Under the
hood, Subspace talks to the kernel directly over zeromq using kernel wire protocol 5.3,
the same protocol Jupyter clients use, with every message HMAC-signed per the kernel’s
connection file. There’s no intermediary jupyter-server: the server process owns the
zeromq sockets and streams execute_request / execute_reply / stream /
display_data messages straight from the kernel to the cell.
Outputs persist
Section titled “Outputs persist”Whatever the kernel returns, text, sandboxed HTML, images, or errors, is captured and
written into the cell’s element.outputs via the setCellOutputs command, the same
command protocol every other element edit uses. Images
land in the content-addressed blob store. Because outputs
are persisted, reopening a page renders the last output immediately without re-running
the cell; execution only happens when you explicitly trigger it again.