01
Tithon — the Jupyter kernel and its entire output history move to a host daemon, so closing the laptop stops mattering
The Show HN (7 points, 3 comments, posted 13:23 UTC Tuesday by rnoro_) opens with the failure everyone with a GPU box has had: "Every time I ran a training loop for a few days via Jupyter Notebook and ran into issues (network disconnected, my laptop suddenly died, etc.), I suffered from losing my ipykernel and cell outputs." The README's framing is the useful part, because it refuses to blame any one tool and names the shared cause instead. JupyterLab reconnects but everything printed while you were away is gone, since "iopub output is streamed over the WebSocket and never persisted server-side, so there is nothing to replay." VSCode Jupyter ties the kernel to the extension-host process, so closing the window kills the kernel. tmux plus jupyter console survives the disconnect but loses rich output and cannot be opened from a second client. "The root cause is the same in all three: the source of truth for your session lives on the client, or in a channel that doesn't outlive a disconnect. Tithon moves it to the host." The implementation is specific enough to argue with. The kernel runs detached under setsid so it is not a child of the daemon, and re-attaches through a persisted connection file when the daemon crashes, restarts, or gets upgraded. Every iopub and shell message is journaled verbatim to append-only SQLite in WAL mode, alongside a per-execution folded snapshot of current display state, so a reconnect is a snapshot plus an ordered gapless delta rather than a replay of everything. Clients attach with the last sequence number they saw. Rich outputs are stored as files referenced by hash and never base64-embedded, ipywidgets traffic is folded into a widget-state+json snapshot so a tqdm bar comes back at its real value, per-subscriber buffers are capped so one slow client cannot grow daemon memory, and the daemon binds a 0600 unix domain socket with no TCP at all. The README demonstrates the claim rather than asserting it: run some code, pkill -9 -f 'tithon daemon', restart it, and tithon attach --since 0 --once brings the earlier output back with kernel state intact.
The VSCode side is where a design decision gets made that will decide whether you want this. The extension opens a percent-format .py — a plain script with # %% markers — as a notebook backed by the daemon, with the same cells and the same rich output as an .ipynb, and outputs are matched to cells by content hash so they survive edits and reopens, with an edited cell's output flagged stale. The .py stays pure source; outputs never touch the file, so diffs stay clean. Asked in-thread why the detachable-kernel architecture went with .py at all, the author was direct: "I wanted to drop the dependency on .ipynb for this version, so I went with .py files instead. The detachable kernel itself isn't tied to .py." The README argues the same choice from the agent angle, that a notebook is roughly 250 lines of "cell_type" and "outputs" noise where the .py is about 50, and that storing output images as real files lets an agent hand the model an actual image instead of base64 it burns thousands of tokens failing to read. Provenance is modest and stated plainly: MIT, Python 3.11+, 161 commits since a June 12 bootstrap, 13 stars, one fork, three contributors, pip install tithon and code --install-extension rnoro.tithon. The banner at the top of the README says "Status: alpha. It works and it's in daily use, but you will hit rough edges." The last push was August 19, three weeks before the Show HN.
Reach for it if you run long jobs in notebooks on a machine you SSH into, which is most people training anything; it replaces the tmux habit you adopted because the notebook kept dying, and it replaces nothing you are currently paying for. Delete the log file you tail in a second window because you stopped trusting the cell output. Tradeoffs: it is Unix-only because the daemon uses unix domain sockets and setsid, with WSL the recommended answer on Windows and native Windows unsupported; the daemon and the extension must share TITHON_HOME on the same host, which a Tunnel or Remote-SSH satisfies for free but a laptop-to-remote-daemon setup does not, leaving you to forward the socket yourself; the journal is append-only SQLite, so a months-long session is a file that grows and the README does not say who prunes it; and the top-voted reply in its own thread is a flat rejection of the premise — "Nah, this is working backwards," from a commenter who would schedule sit-downs with anyone on his team doing this instead of using a job runner, which is a fair description of the fork in the road this pick sits on.