I am announcing this package for anyone to try out, but just copy-pasting the readme. It should be considered beta, but it works well so give it a go! I don’t touch windows much though so there might be more bugs on that side of things.
TLDR: Similar to JupyterHub for Jupyter, but focused on Pluto. Fork of Pluto with terminal and file browser. The reactivity mode is changed just slightly, making it really seamless to work alongside agents on the same notebook without restarts
SpaceStation.jl
A workspace for Pluto notebooks — for humans and agents.
Pluto.jl gives you a reactive notebook.
SpaceStation gives you the space around it: a folder workspace, tabbed notebooks and files,a real terminal, point-and-click SSH remotes, outputs that survive restarts, and first-class human + agent collaboration on one live session — all on the unmodified Pluto editor.
Install & run
SpaceStation installs as a Julia Pkg App — one command puts a real spacestation executable on your PATH, so it launches like any CLI tool (no julia -e …, no manual import):
julia> import Pkg; Pkg.Apps.add("SpaceStation.jl")
$ spacestation # workspace picker
$ spacestation ~/project # open a folder as a workspace
$ spacestation notebook.jl # open a single notebook
$ spacestation --help
Prefer it as a library? import SpaceStation; SpaceStation.run() works too (every Pluto.run keyword applies). Lazy/collab mode is the default; add --autorun for classic Pluto reactivity.
Want to try everything below hands-on? There’s a ready-made demo workspace with a guided
shot list: spacestation-demo.
What SpaceStation adds to Pluto
Everything in this section is something vanilla Pluto doesn’t have. The notebook engine, editor, reactivity, @bind, packages, and the .jl file format are all Pluto’s — and notebooks stay byte-for-byte compatible in both directions. SpaceStation only adds the space around them.
Open a folder as a workspace
SpaceStation starts where an IDE does: a VS Code-style “Open Folder” hub with recent workspaces, a filesystem browser, and (if you have SSH hosts) one-click remotes. Pick a folder and its file tree becomes your sidebar — notebooks and files open as tabs beside it.
Notebooks and files are tabs
Notebooks open as tabs — each one the unmodified Pluto editor in its own session. Plain files open in tabs too, edited with the same CodeMirror — including the per-notebook *.pluto-cache.toml sidecar, which is just readable TOML. Add and delete files right from the tree.
A real, persistent terminal
An integrated PTY shell runs in the workspace folder. Dock it bottom, right, or as an editor tab; and — unlike a browser terminal — it’s a persistent session: refresh the page and the shell keeps running, replaying its scrollback on reconnect (tmux semantics, no tmux). It also exports PLUTOSPACE_PORT/PLUTOSPACE_SECRET and puts pluto-collab on PATH, so a coding agent launched here just works.
SSH remote workspaces
Click a host from your ~/.ssh/config and the entire workspace — files, kernels, terminal, the agent API — runs on that machine over an SSH tunnel. First contact installs SpaceStation on the remote; after that it reconnects instantly. The VS Code Remote-SSH model, with zero config beyond your SSH setup.
Lazy mode: humans and agents on one live session
SpaceStation’s default isn’t autorun. Editing a cell — in the browser or on disk — marks it (and everything downstream) stale instead of running it, so a run executes only the stale closure. Because of that, a human in the browser and a coding agent in a terminal can work on the
same live notebook at once — same kernel, same state. The agent edits the .jl with its normal file tools; the affected cells turn amber within a second in the browser, and a run applies them. No MCP, no plugins — just a small CLI, pluto-collab.
The agent surface is deliberately two-tiered — editing and executing are separate steps:
- Edit → stage. The agent edits the
.jlwith its normal file tools. That only marks the changed cells (and everything downstream) stale — nothing runs. The human watches them turn amber within a second. - Run → apply. An explicit
run --staleexecutes only the stale closure. Separating stage from apply is deliberate: you review what’s about to run, expensive cells don’t fire on every keystroke, and the session stays reproducible.
The mechanism is plain — no MCP, no plugins:
- a connection file at
~/.local/state/pluto/servers/<node>-<port>.json(port + secret — the Jupyter idiom), - a plain HTTP API at
/api/v1/…(curl-able, authed with?secret=…), - a tiny CLI, in two equivalent front-ends:
pluto-collab status nb.jl # Unix shorthand — a bash script (curl + sed)
spacestation collab status nb.jl # any platform incl. Windows PowerShell — built into the app, no deps
# the flow (either front-end — same commands, arguments, and exit codes):
… status nb.jl # REVIEW: per-cell STALE / COLD / ERRORED / output (reflects the file right now)
… run nb.jl --stale # APPLY: run exactly what's outdated (blocks; exit 1 on error)
… output nb.jl --cell <id> # read a cell's full, untruncated output
… figure nb.jl --cell <id> # save a cell's rendered plot to an image file
pluto-collab needs bash + curl (Unix); spacestation collab … is the identical command set built
into the app with no external dependencies, so the surface works the same in a Windows terminal.
Inside a SpaceStation terminal, PLUTOSPACE_PORT / PLUTOSPACE_SECRET point either one at the live
session automatically.
Two guarantees make the loop reliable:
statusalways reflects the file. It re-syncs from disk on every call, so immediately after an edit it reports the true stale set — the review step never lags the ~½-second file watcher.- Runs share the browser’s execution queue. HTTP runs go through the same path as browser clicks, so both sides see cells turn amber → running → green live. Staleness is verified against content-addressed execution keys, so reverting an edit un-stales a cell with no run at all.
See COLLAB.md for the full details and an AGENTS.md stanza you can drop into any repo.
Two files, and outputs that survive restarts
Every notebook is two files: the .jl (your code — the source of truth, unchanged from vanilla Pluto) and a plain-TOML <notebook>.jl.pluto-cache.toml sidecar holding every cell’s output plus its execution key. Reopen a notebook and every output is restored instantly from that sidecar — no recompute. Vanilla Pluto has no output persistence; it either re-runs everything on open or shows nothing.
| With the sidecars → outputs restored on open | Without them → "Code not executed" (plain Pluto) |
rand(), the clock, I/O) opt out with always_stale = true.Relationship to Pluto.jl
SpaceStation is a friendly fork of Pluto.jl. The notebook engine, editor, file format, and reactivity are Pluto’s, and notebooks remain fully compatible in both directions. For everything about notebooks themselves (reactivity, @bind, packages, exporting), see the Pluto documentation. ![]()
SpaceStation adds the space around the notebooks: workspaces, tabs, terminal, remotes, persistence, and first-class human + agent collaboration. --autorun gives you classic Pluto reactivity whenever you want it, byte-for-byte.
SpaceStation is developed and owned by Dale Black / GroupTherapyOrg. It is an independent fork and is NOT developed, maintained, or endorsed by the Pluto.jl team — please direct SpaceStation questions, issues, and feedback to this repository, not to the Pluto developers.
Status
Early and experimental. SpaceStation is under active development by a small team; expect rough edges and breaking changes. Issues and ideas are welcome on this repo.
AI disclosure
Much of SpaceStation’s code is written with AI assistance (Claude). Commits are co-authored accordingly.
License
MIT — see LICENSE. SpaceStation is developed and owned by Dale Black / GroupTherapyOrg. It builds on Pluto.jl (© the Pluto.jl authors — Fons van der Plas and contributors, MIT), which retains its own copyright; the original Pluto license is preserved in LICENSE.







