Notebooks
Open any .ipynb and you get a Jupyter-style notebook UI inline — cells, run, outputs, markdown — without leaving the workspace.
Opening a notebook
Click any .ipynb file in the file tree. The standard code-preview is hidden and the notebook UI mounts in its place.
If you don't have a notebook yet, create one:
echo '{"cells":[],"metadata":{},"nbformat":4,"nbformat_minor":5}' > scratch.ipynb
Then click it in the tree.
The notebook UI
A sticky header sits above the cells with four controls:
- + Code — append a new code cell.
- + Markdown — append a new markdown cell.
- Run All — execute every code cell top to bottom.
- Clear — remove all outputs and reset execution counts.
Each cell has its own toolbar:
[n]— execution count (shows after a run).- ▶ — run this cell.
- ↑ / ↓ — move up / down.
- + — insert a new cell after this one.
- × — delete this cell.
Running cells
- Shift+Enter — run the focused cell.
- Tab inserts 4 spaces (because notebooks).
- Blur — when you click out of a cell, it auto-saves.
Output rendering
The notebook UI handles all four nbformat output shapes:
| Shape | Rendered as |
|---|---|
stream (stdout) | Plain text. |
stream (stderr) | Plain text in a muted-red panel. |
error | Traceback with ename, evalue, frames. |
execute_result / display_data | Priority: image/png → text/html → text/plain. |
Output regions cap at ~360px tall and scroll. Long outputs don't blow up the layout.
Saving
Saves are atomic (.tmp → replace). The notebook is written as plain nbformat v4.5 JSON. You can open the same file in JupyterLab and everything is byte-compatible.
Execution backend
The notebook runtime tries two execution paths:
jupyter_clientif installed in the workspace — gives you a full kernel with state preservation across cells.- Subprocess fallback — each cell is run as
python -I -c <source>with the workspace as CWD. State does not persist across cells in this mode.
Check which is active:
curl -b cookies.txt https://your-workspace.krowforge.com/api/notebook/capabilities
To enable kernel mode:
pip install jupyter_client
# restart the workspace
Cell timeout
Each cell run has a server-side timeout (default 20s, max 300s). Long-running cells raise a TimeoutError and are killed cleanly.
Limitations
- No widgets —
ipywidgetsisn't supported in the inline UI. Use JupyterLab for widget-heavy notebooks. - No magics other than
%matplotlib inlinein subprocess mode. Kernel mode supports any magic the kernel supports. - One notebook open at a time in the workspace's notebook host. Open another
.ipynband it replaces the current one.