Library / SDK
jupyter-xeus/xeus avatar
jupyter-xeus/xeus

xeus: writing a Jupyter kernel in C++ without touching the protocol

Implementation of the Jupyter kernel protocol in C++

961 stars89 forksC++BSD-3-Clause

At a glance

What is it?
xeus is a C++ library that implements the Jupyter kernel protocol so kernel authors can focus on the interpreter side, packaged on conda-forge and used by kernels such as xeus-cling and xeus-python.
Who is it for?
xeus fits teams that already have a C++ interpreter to expose, and it does not fit people who want a ready kernel or who want to write one in Python, where existing kernels already cover that ground.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 32 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

xeus takes over the wire protocol, you keep the interpreter

Every Jupyter kernel, whatever language it runs, ends up speaking the same message protocol: requests arrive over a channel, the kernel does some work, and replies go back with status, payloads and metadata. Writing that plumbing by hand is work that has nothing to do with your language runtime. xeus is a C++ library that removes exactly that part. It implements the Jupyter kernel protocol so that a developer can concentrate on the interpreter part of the kernel, which is the part that actually runs the code. The library is not a kernel and it does not start a notebook by itself. It is the layer underneath one. That placement matters for evaluation: nobody installs xeus to get a notebook, they install it to build a kernel for an interpreter that already exists, and the documentation site is xeus.readthedocs.io.

Seven virtual methods are the entire contract with the front end

The starting point for a new kernel is the base interpreter class xeus::xinterpreter. You inherit from it and implement a set of private virtual methods, and those methods are the whole surface that the front end can ask for. The list is short enough to hold in your head: configure_impl, execute_request_impl, complete_request_impl, inspect_request_impl, is_complete_request_impl, kernel_info_request_impl and shutdown_request_impl. The skeleton of a custom interpreter looks like this, with the class declared inside a custom namespace and the JSON library brought in under the alias nl.

cpp
#include "xeus/xinterpreter.hpp"

#include "nlohmann/json.hpp"

using xeus::xinterpreter;

namespace nl = nlohmann;

namespace custom
{
    class custom_interpreter : public xinterpreter
    {
    public:

        custom_interpreter() = default;
        virtual ~custom_interpreter() = default;

The next block continues the same class with the private overrides that the documentation expects to see.

execute_request_impl receives a callback, a counter and a JSON payload

The execution hook is the widest of the seven, and its signature shows how much xeus hands to the kernel author. It takes a send_reply_callback, an execution counter, the code as a string, an execute_request_config and a user_expressions object of type nl::json. The callback is how the interpreter answers: you invoke it with the payload that should travel back to the front end. The remaining overrides are smaller. Completion and inspection take the code plus a cursor position, and inspection adds a detail level. is_complete_request_impl returns whether the snippet is finished, kernel_info_request_impl returns metadata about the kernel itself, and shutdown_request_impl takes a restart flag. The class also declares an interrupt_request_impl override for handling interruption.

cpp
        void execute_request_impl(send_reply_callback cb,
                                  int execution_counter,
                                  const std::string& code,
                                  execute_request_config config,
                                  nl::json user_expressions) override;

        nl::json complete_request_impl(const std::string& code,
                                       int cursor_pos) override;

        nl::json inspect_request_impl(const std::string& code,
                                      int cursor_pos,
                                      int detail_level) override;

Notice that none of these signatures are tied to a particular language. The JSON types are the only vocabulary xeus imposes, which is what lets the same skeleton serve a C++ interpreter, a Python one, or something else entirely.

Rebinding to native APIs beats capturing printed text

The classic way to expose a language to Jupyter is a wrapper that runs the interpreter and captures whatever it prints as text. That works, but it throws away everything that is not a string. Once a kernel author inherits from xeus::xinterpreter, the kernel can rebind to the native APIs of the interpreter it is interfacing with, and that is where the richer information comes from. A completion request can come from the interpreter's own completion machinery rather than from a text guess. An inspection request can return the real type and signature of an object instead of a stringified representation. The comparison is explicit in the documentation, which frames the native rebinding as providing richer information than the classical approach of a wrapper kernel capturing textual output. If your interpreter already has a completion engine, an object model or a debugger interface, this is where xeus pays off, and if it does not, the advantage shrinks to protocol convenience.

Building from source means cmake plus a conda-forge dependency set

The packaged route is one command, because xeus has been packaged for all platforms on the mamba or conda package manager.

bash
mamba install xeus -c conda-forge

Building it yourself takes a little more. The stated dependencies can be installed from the same channel.

bash
mamba install cmake pkg-config xtl nlohmann_json -c conda-forge

On Linux platforms there is one extra requirement, libuuid, which is available in all Linux distributions and comes from the uuid-dev package on Debian.

bash
mamba install libuuid -c conda-forge

With the dependencies in place, the build itself is the standard cmake sequence run from the build directory.

bash
cmake -D CMAKE_BUILD_TYPE=Release ..
make
make install

The repository layout supports that flow directly: a CMakeLists.txt at the root, a cmake directory, the public headers under include, the implementation under src, a test directory and a xeusConfig.cmake.in file that carries the package configuration to consumers.

The dependency matrix shrank as xeus moved past version 3

The dependency tables in the documentation tell a story about how the transport layer was handled over time. For master and the 6.x line, the listed requirement is nlohmann_json ^3.12.0. The 5.x line asks for the same library at ^3.11.0. Versions before 5 also pull in xtl, and the 4.x and 3.x lines want xtl between 0.7.0 and 0.8.0. Versions prior to 3 also depend on ZeroMQ, cppzmq and OpenSSL, and the 1.x and 2.x lines carry explicit pins for all three: ZeroMQ ^4.2.5, cppzmq ^4.7.1, OpenSSL ^1.0.1, xtl >=0.7.0,<0.8.0 and nlohmann_json ^3.2.0. ZeroMQ is described as the messaging library underlying the Jupyter kernel protocol, and the instructions for building it from source still sit in the documentation, together with separate cmake and make recipes for the header only libraries cppzmq, nlohmann_json and xtl. The practical consequence for an adopter is that the dependency surface you inherit depends on the major version you pin, so a 6.x integration does not carry the ZeroMQ build chain.

xeus gives you no kernel of its own, and that is the whole trade-off

Here is the limitation worth stating plainly. xeus is a library, so installing it leaves you with a C++ dependency and no runnable kernel. Everything a front end can ask for, you implement yourself in the seven methods, including the parts that are tedious rather than interesting: kernel info replies, shutdown handling and completion fallback behaviour. There is no scaffolding command that generates a working kernel for you, and the documentation points to the full guide rather than to a generator. The alternative for many teams is not another library but an existing kernel. Two kernels are built on xeus: xeus-cling, a kernel for the C++ programming language, and xeus-python, an alternative Python kernel for Jupyter. If one of those fits your runtime, the work of adopting xeus is already done for you, and writing your own interpreter on top of xeus is only justified when you need control that those kernels do not give you.

Release cadence and licence terms for a kernel foundation

The 6.x line arrived as a tight cluster of releases in March 2026: v6.0.0 and v6.0.1 on the same day, 2026-03-04, and v6.0.2 on 2026-03-06. The last push to the repository was on 2026-09-21, so the 6.x series is the version to target when you start something new, and older major versions are there for existing integrations. The licence is BSD-3-Clause, which is the permissive family that most C++ infrastructure is published under and that lets you ship a proprietary kernel built on top of it without a copyleft obligation. Two supporting files sit alongside the code for anyone embedding the library: a CONTRIBUTING.md with the contribution process and an xeusConfig.cmake.in template that a downstream kernel package uses when it installs xeus. Development also touches continuous integration through a GitHub Actions workflow in the .github directory, and environment files for development and for the wasm build exist at the root.

Editorial conclusion

xeus fits teams that already have a C++ interpreter to expose, and it does not fit people who want a ready kernel or who want to write one in Python, where existing kernels already cover that ground. Verify three things before you start: that your interpreter can be driven from C++ rather than through a subprocess, that the seven virtual methods are enough for the requests your front end sends, and that the conda-forge package version matches the xeus major version you are coding against. The last push was on 2026-09-21, the 6.x line was released in March 2026, and the code is under BSD-3-Clause.

Frequently asked questions

How do I install xeus?

xeus has been packaged for all platforms on the mamba or conda package manager. Run mamba install xeus -c conda-forge, or build it from source with cmake after installing its dependencies.

What does a kernel author have to implement when using xeus?

You inherit from the base interpreter class xeus::xinterpreter and implement private virtual methods including configure_impl, execute_request_impl, complete_request_impl, inspect_request_impl, is_complete_request_impl, kernel_info_request_impl and shutdown_request_impl.

Which Jupyter kernels are built on xeus?

xeus-cling, a kernel for the C++ programming language, and xeus-python, an alternative Python kernel for Jupyter. Both are listed as kernels built upon xeus.

Official sources

  1. jupyter-xeus/xeus on GitHub
  2. License: BSD-3-Clause
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jupyter-xeus-xeus.svg)](https://hysenlabs.com/projects/jupyter-xeus-xeus)