Stream: ideas

Topic: Jupyter kernel for Roc


view this post on Zulip Aurélien Geron (Jul 02 2026 at 07:38):

I've started implementing a Jupyter kernel for Roc. I've got a first version running. It's not quite ready for prime-time yet, but here's a teaser:

roc-kernel.mov

view this post on Zulip Jonathan (Jul 02 2026 at 08:19):

How does jupyter work with functional langs and immutability? I'm not sure how to phrase the question other than by example - the notebooks I use with Elixir must execute in sequence, and rerunning a cell only captures variable state from earlier cells and not any that have been reassigned. This prevents the number of times, or sequence you have run cells, from being a concern except for external effects. Can you control this kind of behaviour with a jupyter kernel (if desirable)? I imagine it might be interesting with Roc with vars too, but lack of shadowing does prevent the badness I'm thinking of.

view this post on Zulip Aurélien Geron (Jul 02 2026 at 09:00):

Basically a Jupyter kernel is a little server that communicates over 5 ZeroMQ sockets:

I've plugged into the Roc REPL so it's exactly like a regular Roc REPL session. In the REPL, you can redefine a function (which is what I demo near the end of the video by redefining the square function to return xxx. I don't know how the REPL does that.

view this post on Zulip Aurélien Geron (Jul 02 2026 at 09:32):

For example, when I ran square(3), the code came in through the Shell socket. The kernel immediately broadcast status (busy) over the IOPub socket. The Roc compiler evaluated the code, and the kernel pushed the "9" out over IOPub. Finally, the kernel told IOPub to broadcast status (idle) and told Shell that the request was complete. Meanwhile, Heartbeat was pinging in the background to keep the connection alive.

view this post on Zulip Aurélien Geron (Jul 02 2026 at 10:08):

There are various ways to build a Jupyter kernel. Here are a few options:

image.png

JMP means Jupyter Messaging Protocol.

Option A is the simplest: the kernel just launches a roc repl and uses stdin/stdout to send commands to it, and capture the responses. It's cool for a proof of concept, but it's brittle (any change to the REPL's UI will break it) and it doesn't allow the full set of Jupyter features (e.g., no autocomplete).

Option B would improve greatly on option A: instead of capturing the REPL's stdin/stdout, Roc could have a special mode which would give access to all of its REPL features through a programmatic interface, such as JSON RPC. The kernel would launch something like roc eval-server and communicate with it. Any tool can query it using JSON RPC.

Option C is the same as Option B but it uses the JMP protocol instead of JSON RPC. This means that the roc binary integrates the Jupyter kernel directly: you run roc jupyter and it acts as a Roc kernel, serving the 5 ZMQ sockets I listed earlier. Any JMP-compatible tool can use it.

Option D: the kernel lives separately from the main code, but it is based on the same Zig libraries. This is what I have implemented to get started, but the downside is that the kernel needs to be recompiled every time the Roc compiler changes. Moreover, it makes the kernel quite large since it includes Roc.

Wdyt?

view this post on Zulip Jonathan (Jul 02 2026 at 21:32):

Oh I couldn't say :smile: but thank you I now understand Jupyter better!

view this post on Zulip Aurélien Geron (Jul 03 2026 at 06:31):

I implemented option B in draft PR #9923: running roc repl --rpc will make the REPL wait for JSON commands and output JSON outputs, for example:

% roc repl --rpc
{"method": "repl.start", "id": "req001"}
{"session_id":"68da396c-9302-4d2a-a800-a3b644665c68","id":"req001"}
{"method": "repl.evaluate", "params": {"session_id": "68da396c-9302-4d2a-a800-a3b644665c68", "code": "2 + 2"}, "id": "req003"}
{"result":"4.0","stdout":"","diagnostics":null,"id":"req003"}
{"method": "repl.stop", "params": {"session_id": "68da396c-9302-4d2a-a800-a3b644665c68"}, "id": "req004"}
{"success":true,"id":"req004"}

I built a Roc kernel for Jupyter based on this RPC mode. Feel free to try it out, you should have an experience similar to the video I posted earlier in this thread. You need to compile Roc with the draft PR #9923, and follow the build & install instructions for the Roc kernel.

view this post on Zulip Aurélien Geron (Jul 03 2026 at 06:33):

@Richard Feldman said that he'd rather not introduce JSON into any of our CLI or compiler outputs. I'm happy to change the draft PR: what other options do we have to ensure that the REPL can be controlled programmatically?

I went this JSON-RPC route because I believe that's how the LSP works? Actually, perhaps we could just extend the LSP to support these extra methods (start/stop/reset a session and evaluate some code in a given session)?

view this post on Zulip Luke Boswell (Jul 03 2026 at 08:34):

We could add support for a repl "plugin" script like roc glue maybe? and then handle the json inside that?

view this post on Zulip Luke Boswell (Jul 03 2026 at 08:35):

Or maybe this is something roc tooling could help with?

view this post on Zulip Luke Boswell (Jul 03 2026 at 08:35):

Idk ... just throwing some ideas around

view this post on Zulip Aurélien Geron (Jul 03 2026 at 08:44):

I'm not familiar with roc glue or roc tooling. I believe that roc experimental-lsp starts a JSON RPC server (JSON objects in through stdin, JSON objects out through stdout), so I figured that this was the way to go, since it's very similar functionality (i.e., the LSP provides static info & features, while the REPL-RPC provides dynamic features).

view this post on Zulip Richard Feldman (Jul 03 2026 at 14:41):

yeah I don't want us to

view this post on Zulip Richard Feldman (Jul 03 2026 at 14:41):

have lsp in the CLI either :sweat_smile:

view this post on Zulip Richard Feldman (Jul 03 2026 at 14:41):

in general I want to follow glue's example

view this post on Zulip Richard Feldman (Jul 03 2026 at 14:41):

where you write roc code to transform into whatever format you need (json etc)

view this post on Zulip Norbert Hajagos (Jul 03 2026 at 22:04):

Luke Boswell said:

We could add support for a repl "plugin" script like roc glue maybe? and then handle the json inside that?

I'm also not familiar with how glue works, but what comes to mind is a built in platform that is coupled to the compiler. You could only use it if you version it correctly in your app, but other than that, it would give you programatic access to the repl.
As I'm typing this, the question arises: how do we do IO in such an application? And that is a rabit hole where the compiler includes a builtin platform with every possible io type, so I immediately dislike my idea.

How would the plugin approach work?

view this post on Zulip Richard Feldman (Jul 03 2026 at 22:07):

for something like this I assume we wouldn't support arbitrary I/O

view this post on Zulip Richard Feldman (Jul 03 2026 at 22:07):

glue is like "give me a list of output files you want, and their contents, and I will write them to disk" and I think it has restrictions on where they can go (e.g. must be a subdirectory of the current dir or something)

view this post on Zulip Luke Boswell (Jul 04 2026 at 01:27):

Yes roc glue is what I have been calling the "plugin" use-case... there are no prebuilt host files in the platform, the roc cli itself embeds the roc compiler (it's already there for roc build etc) and compiles the app and runs the script.

This is a pattern I have used elsewhere too, like another totally unrelated program that runs the roc apps instead of the roc cli building standalone binaries.

view this post on Zulip Luke Boswell (Jul 04 2026 at 01:29):

In future you could imagine libroc for doing this more easily, but for now you can wrap the roc modules using a zig program easy by pointing it at the roc-lang/roc repo.

view this post on Zulip Luke Boswell (Jul 04 2026 at 01:30):

The LSP is currently named experimental, because the long term goal is to remove all that logic from the compiler, and decouple that. So the LSP can upgrade independently etc.

view this post on Zulip Aurélien Geron (Jul 04 2026 at 16:19):

I'm happy to follow the Roc glue path, but I'm not sure I have a good understanding of the architecture we're shooting for. Is it the option D in my diagram above? Basically the Roc eval tools would be compiled directly into the Roc kernel?

view this post on Zulip Aurélien Geron (Jul 06 2026 at 07:57):

I've already implemented option D, where the Roc kernel simply uses the Roc compiler code to evaluate the cells directly, without using the Roc CLI at all. It works fine, but it has two drawbacks:

  1. Every time the Roc compiler changes, we must build and deploy the new Roc kernel. Jupyter kernels for other languages typically don't change much since they just proxy code from Jupyter to the target language's interpreter or compiler. For the end user, bumping the language version just requires updating one thing, not two.
  2. The Roc kernel is quite large for a Jupyter kernel: 200 MB. Since most kernels are just simple proxies, they are typically quite small.

I still haven't really understood the alternative "roc-glue-like" architecture you have in mind. Would someone be kind enough to draw a picture? It sounds to me like it's similar to Option D, so it would still have these two issues, wouldn't it? I'm not pushing back, I'm just confused.

view this post on Zulip Jonathan (Jul 06 2026 at 09:25):

I am also not entirely sure, thinking out loud for what it's worth? I don't know how 'glue like' it is, but the repl could operate like the elm architecture, where a plugin receives/subscribes to repl events, and emits actions (or directly calls effectful host functions not sure) etc, like "evaluate snippet" or "write these bytes to a socket". The compiler supplies the repl platform, and expects the plugin to expose handlers etc. I think you would be able to supply this to Roc like roc repl --plugin jupyter.roc, and the terminal repl could be a bundled terminal.roc plugin?

view this post on Zulip Jonathan (Jul 06 2026 at 09:44):

I think this is along the lines of what Luke meant - the repl plugin is compiled against a platform, but stops short of linking against it and instead roc drives it directly? This is also my very rough understanding of the glue pipeline.

view this post on Zulip Luke Boswell (Jul 06 2026 at 09:53):

There's definitely some design questions here about what are the effects or the API for this kind of functionality

view this post on Zulip Richard Feldman (Jul 06 2026 at 12:58):

Aurélien Geron said:

I still haven't really understood the alternative "roc-glue-like" architecture you have in mind. Would someone be kind enough to draw a picture? It sounds to me like it's similar to Option D, so it would still have these two issues, wouldn't it? I'm not pushing back, I'm just confused.

yeah sorry, I haven't really had time to dig deeply into this...the basic idea is:

view this post on Zulip Richard Feldman (Jul 06 2026 at 12:59):

so if you wanted to go the JSON route, you could implement that function to take the Foo and Bar structs from the compiler and just have the Roc function serialize them as JSON and return that, at which point you have the same interface to Jupyter as the original PR (but with the indirection of having the Roc code say "I want to turn this into JSON" instead of having that be hardcoded in the compiler)

view this post on Zulip Richard Feldman (Jul 06 2026 at 13:00):

but it also opens up other possibilities, e.g. you could make the Roc code not be restricted to just returning a Str that gets printed to stdout, you could do things like have it describe what bytes to send over a socket, and the CLI could take care of opening that socket for you, watching the filesystem, and just calling the Roc function repeatedly whenever things change

view this post on Zulip Richard Feldman (Jul 06 2026 at 13:01):

does that make sense?

view this post on Zulip Aurélien Geron (Jul 06 2026 at 14:52):

Ah, that makes complete sense, thanks for the detailed explanation @Richard Feldman . :folded_hands:
So the Jupyter kernel could remain exactly the same as today, but instead of calling roc repl --rpc, it would call something like roc repl json-rpc.roc.

Would the json-rpc.roc script be based on the CLI platform to read from stdin and write to stdout? If so, how would it interface with Roc's REPL (for the Foo and Bar data structures)? Or should I develop a Roc platform designed for this use-case, which would provide both Stdin/Stdout and the REPL interface?

view this post on Zulip Richard Feldman (Jul 06 2026 at 14:53):

is it literally just taking in repl inputs and responding with output?

view this post on Zulip Richard Feldman (Jul 06 2026 at 14:53):

if so, we could abstract it more than that - like it just receives a Str from the repl and then returns a Str for what to output, for example

view this post on Zulip Aurélien Geron (Jul 06 2026 at 15:02):

Yes, the core functionality is just Str in, Str out, but kernels typically offer a few more functionalities, including auto-complete and type info.

view this post on Zulip Aurélien Geron (Jul 06 2026 at 15:08):

Oh and there can also be rich outputs, like HTML, images, and even interactive outputs (HTML+JavaScript).

view this post on Zulip Richard Feldman (Jul 06 2026 at 15:53):

I'd say let's start with just the core functionality then

view this post on Zulip Richard Feldman (Jul 06 2026 at 15:53):

like basically a way to drive the repl programmatically

view this post on Zulip Aurélien Geron (Oct 10 2026 at 07:10):

I'm back to working on iRoc, a Jupyter kernel for Roc. As discussed, I've replaced the --rpc option based on JSON with a --formatter option that takes a Roc script, such as json-repl-formatter.roc. Here's a sneak preview:
iRoc-demo.mov

view this post on Zulip Jonathan (Oct 10 2026 at 08:30):

Away from the computer so I'll have to try this later! But I have questions:

view this post on Zulip Aurélien Geron (Oct 10 2026 at 09:03):

This sounds about right, I'll test it asap.

Edit: the first point is exactly right. However, the second is not, as I get a ✗ var outside body error when trying to define a var outside a block or function. This matches the behavior of the REPL.

view this post on Zulip Aurélien Geron (Oct 10 2026 at 10:27):

If you want to try it out (you'll need Zig 0.17.0 and Python 3.10+):

# Build Roc with formatter support.
git clone --branch add-repl-structured-values --single-branch \
  https://github.com/ageron/roc.git roc-iroc
cd roc-iroc
zig build roc -Doptimize=ReleaseFast
IROC_COMPILER="$PWD/zig-out/bin/roc"
cd ..

# Install iRoc and JupyterLab in a virtual environment.
git clone https://github.com/ageron/iRoc.git
cd iRoc
python3 -m venv .venv
source .venv/bin/activate
python -m pip install . jupyterlab
python -m iroc install --user --roc "$IROC_COMPILER"

jupyter lab

view this post on Zulip Aurélien Geron (Oct 11 2026 at 09:53):

You can now run Roc on Colab! :roc:

image.png

view this post on Zulip Aurélien Geron (Oct 11 2026 at 10:03):

Colab notebooks could be a convenient format for Roc tutorials.

view this post on Zulip Anton (Oct 11 2026 at 10:05):

Notebooks could be great for https://github.com/roc-lang/examples too

view this post on Zulip Luke Boswell (Oct 11 2026 at 10:06):

Is it possible to give collab notebooks syntax highlighting? Id be happy to help if we need anything

view this post on Zulip Aurélien Geron (Oct 11 2026 at 10:08):

The main problem with Colab is that it only supports Julia, Python, and R by default (which are the 3 languages that inspired the name Jupyter, btw). This means that there's a mandatory setup phase (it currently lasts ~45 seconds) which may dissuade new users. There are other platforms such as MyBinder that let you run containers, they're more flexible but I've found them to be a bit slow to start and not always reliable.

view this post on Zulip Aurélien Geron (Oct 11 2026 at 10:12):

Luke Boswell said:

Is it possible to give collab notebooks syntax highlighting? Id be happy to help if we need anything

Sadly there's no official way to do that. That said, a Colab runtime gives the user root access so certainly possible to hack it (after all, it doesn't officially support Roc either, but it works).

view this post on Zulip Anton (Oct 11 2026 at 10:19):

Can't we make our own simple notebook that uses the wasm compiler?

view this post on Zulip Aurélien Geron (Oct 11 2026 at 10:20):

I'd love that!

view this post on Zulip Luke Boswell (Oct 11 2026 at 10:23):

We have the REPL being bundled into the nightlies now dont we?

view this post on Zulip Luke Boswell (Oct 11 2026 at 10:23):

oh, that never landed https://github.com/roc-lang/nightlies/pull/31

view this post on Zulip Aurélien Geron (Oct 11 2026 at 10:24):

If we're going to make a Roc notebook, I think it should be reactive, like Livebook (elixir).

view this post on Zulip Aurélien Geron (Oct 11 2026 at 10:26):

Luke Boswell said:

We have the REPL being bundled into the nightlies now dont we?

Oh you mean the REPL in WASM? Cool.

view this post on Zulip Aurélien Geron (Oct 11 2026 at 10:26):

Although I think that a notebook is more than a REPL: it's literate programming.

view this post on Zulip Luke Boswell (Oct 11 2026 at 10:27):

This was that REPL you helped me design the API for to support a notebook experience

view this post on Zulip Aurélien Geron (Oct 11 2026 at 10:27):

Oh I forgot that we had talked about a WASM version, right!

view this post on Zulip Luke Boswell (Oct 11 2026 at 10:28):

I haven't looked at it in a while, it was blocked from merging at the time or something and I got distracted working on other things

view this post on Zulip Arya Elfren (Oct 11 2026 at 15:15):

Aurélien Geron said:

If we're going to make a Roc notebook, I think it should be reactive, like Livebook (elixir).

Other pre-existing reactive notebooks to learn from include Pluto.jl (Julia) and marimo (Python).

Specifically, I like marimo's usage of plain Python files as the storage format, it lets you: run tests, run formatters, run them headless as scripts, use git (versioning, diffs...) and other plain text tools, import cells (and their ancestors) from other notebooks, import whole notebooks (e.g. an interactive UI)...

view this post on Zulip Aurélien Geron (Oct 12 2026 at 06:30):

Here's the Roc tutorial on Colab

view this post on Zulip Luke Boswell (Oct 12 2026 at 06:35):

image.png

That sounds concerning at first glance...

view this post on Zulip Aurélien Geron (Oct 12 2026 at 06:38):

Yeah, Colab always displays this warning. :face_with_diagonal_mouth:
I guess the notebook code could try to hack the Pentagon or something.
Plus, it could try to access your Google Drive or Colab secrets: in these cases, you get a permission prompt, but it might not be clear to some users that they are trusting the notebook's author (not Google) with their personal data. Hence this message. Perhaps they should only display it when the notebook tries to access something personal.

view this post on Zulip Peter Marreck (Oct 14 2026 at 00:19):

anything that reduces Python footprint is automatically an improvement /opinion ;)

view this post on Zulip Aurélien Geron (Oct 14 2026 at 01:11):

Haha, I understand where you're coming from, but I personally love Python, especially for ML and scripting. I've used a bunch of languages, and Python is still in my top 3. It's main strength is expressivity: it's both incredibly concise and clear. However, it's slow and unsafe, so it's definitely not well suited for every use case.
I think we should take inspiration from the things it did well, such as super handy syntax for the most common data structures (tuples, sets, dicts...), the batteries included philosophy, the flat-better-than-nested philosophy, and in fact virtually all of the Zen of Python (which Roc is well aligned with). There's a reason it is one of the most popular languages out there.

view this post on Zulip TeaDrinkingProgrammer (Oct 14 2026 at 07:56):

Completely agree, plus "typed" Python is all that plus ~80% of the safety guarantees of say C#. That is, Ruff and Ty on toughest settings. As a fan of statically typed languages, I was surprised by how pleasant modern Python is, even compared to something like Typescript that, according to most people, should be better at this. One of my goals/dreams for Roc is to carry that philosophy and the smooth and simple experience of Pydantic + FastAPI + Datastar to Roc


Last updated: Oct 15 2026 at 17:56 UTC