<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Jupyter Blog - JupyterHub</title><link href="https://blog.jupyter.org/" rel="alternate"/><link href="https://blog.jupyter.org/feeds/tag-jupyterhub.atom.xml" rel="self"/><id>https://blog.jupyter.org/</id><updated>2026-09-11T08:54:00+00:00</updated><subtitle>JupyterHub, which serves Jupyter to groups of users.</subtitle><entry><title>JupyterHub 6.0</title><link href="https://blog.jupyter.org/posts/2026/jupyterhub-6-0/" rel="alternate"/><published>2026-09-11T08:54:00+00:00</published><updated>2026-09-11T08:54:00+00:00</updated><author><name>Serena Bonaretti</name></author><id>tag:blog.jupyter.org,2026-09-11:/posts/2026/jupyterhub-6-0/</id><summary type="html">&lt;p&gt;JupyterHub is a collection of tools that provides standardized, user-friendly computing environments for education and research. Today, we’re pleased to announce the release of JupyterHub 6.0. This is a substantial release with several new features.&lt;/p&gt;</summary><content type="html">&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2026/jupyterhub-6-0/images/001-1_l3xTI5FmlszK3So0jg0-YA.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://jupyterhub.readthedocs.io"&gt;JupyterHub&lt;/a&gt; is a collection of tools that provides standardized, user-friendly computing environments for education and research. Today, we’re pleased to announce the release of &lt;a href="https://jupyterhub.readthedocs.io/en/stable/reference/changelog.html#id2"&gt;&lt;strong&gt;JupyterHub 6.0&lt;/strong&gt;&lt;/a&gt;. This is a substantial release with several new features. The breaking changes ought to be minimal, and should affect very few deployments. There is a small database schema upgrade, so make sure to backup your database prior to upgrading, as usual.&lt;/p&gt;
&lt;p&gt;Some changes to highlight:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stricter named server rules&lt;/strong&gt;: Named servers now have stricter rules on their names, and a new less-restricted “display name” field. This might be the &lt;strong&gt;most significant change&lt;/strong&gt; affecting you! See the &lt;a href="https://jupyterhub.readthedocs.io/en/6.0.0/howto/upgrading-v6.html#named-server-restrictions"&gt;documentation&lt;/a&gt; for more details.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Python 3.10 and database upgrade&lt;/strong&gt;: JupyterHub 6.0 now requires Python 3.10 and includes a database schema upgrade. Make sure to &lt;strong&gt;back up your database&lt;/strong&gt; before upgrading.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Updates to metrics&lt;/strong&gt;: The old StatsD metrics have been removed, in favor of the Prometheus metrics that most people are already using. For Spawner (and spawn hook) authors, JupyterHub 6.0 also introduces &lt;a href="https://jupyterhub.readthedocs.io/en/6.0.0/reference/spawners.html#exception-handling"&gt;SpawnException&lt;/a&gt;, which provides more granular information for classifying spawn failures in metrics, to help deployments separate &lt;em&gt;errors&lt;/em&gt; from &lt;em&gt;rejections&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Internal communication changes&lt;/strong&gt;: JupyterHub now uses &lt;em&gt;aiohttp&lt;/em&gt; for internal HTTP requests, which may require tuning for large deployments since internal HTTP requests. This update has facilitated using unix sockets for internal communication on single-node deployments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Improved granularity in API access&lt;/strong&gt;: JupyterHub provides new API endpoints for working with single servers, along with more flexible ways to define permissions, such as &lt;code&gt;start:servers&lt;/code&gt; scope and &lt;code&gt;extra_user_scopes&lt;/code&gt;.&lt;br&gt;
See the &lt;a href="https://jupyterhub.readthedocs.io/en/stable/rbac/roles.html#overriding-default-roles"&gt;documentation&lt;/a&gt; for more information.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Beyond these main changes, there have been lots of other improvements and bugfixes. You can find more details in the &lt;a href="https://jupyterhub.readthedocs.io/en/stable/howto/upgrading-v6.html"&gt;upgrading documentation&lt;/a&gt; and &lt;a href="https://jupyterhub.readthedocs.io/en/stable/reference/changelog.html#changelog"&gt;changelog&lt;/a&gt;.&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
&lt;h2 id="thank-you-to-our-contributors"&gt;Thank you to our contributors&lt;/h2&gt;
&lt;p&gt;The following people contributed discussions, new ideas, code and documentation contributions, and review: &lt;a href="https://github.com/agoose77"&gt;agoose77&lt;/a&gt;, &lt;a href="https://github.com/anny0811"&gt;anny0811&lt;/a&gt;, &lt;a href="https://github.com/ateucher"&gt;ateucher&lt;/a&gt;, &lt;a href="https://github.com/betatim"&gt;betatim&lt;/a&gt;, &lt;a href="https://github.com/bl-aire"&gt;bl-aire&lt;/a&gt;, &lt;a href="https://github.com/clhedrick"&gt;clhedrick&lt;/a&gt;, &lt;a href="https://github.com/consideRatio"&gt;consideRatio&lt;/a&gt;, &lt;a href="https://github.com/dometto"&gt;dometto&lt;/a&gt;, &lt;a href="https://github.com/dragz"&gt;dragz&lt;/a&gt;, &lt;a href="https://github.com/erawn"&gt;erawn&lt;/a&gt;, &lt;a href="https://github.com/ericvd-ucb"&gt;ericvd-ucb&lt;/a&gt;, &lt;a href="https://github.com/jezwilkinson"&gt;jezwilkinson&lt;/a&gt;, &lt;a href="https://github.com/jnywong"&gt;jnywong&lt;/a&gt;, &lt;a href="https://github.com/jrdnbradford"&gt;jrdnbradford&lt;/a&gt;, &lt;a href="https://github.com/kellyrowland"&gt;kellyrowland&lt;/a&gt;, &lt;a href="https://github.com/kreuzert"&gt;kreuzert&lt;/a&gt;, &lt;a href="https://github.com/LUC4R4T0R"&gt;LUC4R4T0R&lt;/a&gt;, &lt;a href="https://github.com/manics"&gt;manics&lt;/a&gt;, &lt;a href="https://github.com/mayli"&gt;mayli&lt;/a&gt;, &lt;a href="https://github.com/milliams"&gt;milliams&lt;/a&gt;, &lt;a href="https://github.com/minrk"&gt;minrk&lt;/a&gt;, &lt;a href="https://github.com/mynkyu"&gt;mynkyu&lt;/a&gt;, &lt;a href="https://github.com/nsychev"&gt;nsychev&lt;/a&gt;, &lt;a href="https://github.com/Paul2708"&gt;Paul2708&lt;/a&gt;, &lt;a href="https://github.com/Rameshkumar31595"&gt;Rameshkumar31595&lt;/a&gt;, &lt;a href="https://github.com/rgaiacs"&gt;rgaiacs&lt;/a&gt;, &lt;a href="https://github.com/shaneknapp"&gt;shaneknapp&lt;/a&gt;, &lt;a href="https://github.com/sixonenines"&gt;sixonenines&lt;/a&gt;, &lt;a href="https://github.com/tbizouerne"&gt;tbizouerne&lt;/a&gt;, &lt;a href="https://github.com/Tech-Abhang"&gt;Tech-Abhang&lt;/a&gt;, &lt;a href="https://github.com/wilkinvr"&gt;wilkinvr&lt;/a&gt;, &lt;a href="https://github.com/willingc"&gt;willingc&lt;/a&gt;, &lt;a href="https://github.com/yuvipanda"&gt;yuvipanda&lt;/a&gt;&lt;/p&gt;
</content><category term="JupyterHub"/><category term="releases"/></entry><entry><title>Positron Server available for academic use via JupyterHub</title><link href="https://blog.jupyter.org/posts/2026/positron-server-available-for-academic-use-via/" rel="alternate"/><published>2026-07-29T18:19:00+00:00</published><updated>2026-07-31T12:28:00+00:00</updated><author><name>Jupyter Foundation</name></author><id>tag:blog.jupyter.org,2026-07-29:/posts/2026/positron-server-available-for-academic-use-via/</id><summary type="html">&lt;p&gt;Academic institutions can now offer Positron directly within their existing JupyterHub environments, giving students access to a modern, full-featured data science IDE without requiring local installation or additional infrastructure.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;em&gt;Editor’s note: This is a guest blog post from Posit, a &lt;a href="https://jupyterfoundation.org/"&gt;Jupyter Foundation&lt;/a&gt; member&lt;/em&gt;&lt;/p&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2026/positron-server-available-for-academic-use-via/images/001-1_1jHlCkiGYDfmAd0mWDhf1A.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;Academic institutions can now offer &lt;a href="https://positron.posit.co/"&gt;Positron&lt;/a&gt; directly within their existing JupyterHub environments, giving students access to a modern, full-featured data science IDE without requiring local installation or additional infrastructure. Licensed under the permissive, source-available &lt;a href="https://positron.posit.co/licensing.html"&gt;Elastic License 2.0&lt;/a&gt;, Positron as a desktop app is free for everyone to use, build on, and extend across personal, academic, and commercial projects. Through a free educational license, universities and other academic organizations can additionally make &lt;a href="https://positron.posit.co/education.html"&gt;Positron Server&lt;/a&gt; available to currently enrolled students for coursework, helping create a consistent learning experience across classrooms, labs, and remote environments.&lt;/p&gt;
&lt;p&gt;By integrating Positron into JupyterHub, educators can provide students with a powerful development environment alongside the tools they already use. Students simply launch Positron from the JupyterHub interface, just as they would open JupyterLab or a different environment, and can begin working immediately.&lt;/p&gt;
&lt;h2 id="bringing-a-modern-data-science-ide-to-the-classroom"&gt;Bringing a Modern Data Science IDE to the Classroom&lt;/h2&gt;
&lt;p&gt;Positron combines the familiarity of notebook-based workflows with the capabilities of a professional integrated development environment (IDE). Once launched through JupyterHub, students have access to the complete Positron experience, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Comprehensive support for both Python and R&lt;/li&gt;
&lt;li&gt;Access to the OpenVSX extension marketplace&lt;/li&gt;
&lt;li&gt;Built-in data viewer and variables explorer&lt;/li&gt;
&lt;li&gt;Integrated help pane, debugging tools, and version control&lt;/li&gt;
&lt;li&gt;Advanced development features that help students grow their data science skills over time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This approach allows instructors to standardize course environments while reducing the technical barriers often associated with software installation and configuration.&lt;/p&gt;
&lt;h2 id="designed-to-work-with-existing-jupyterhub-deployments"&gt;Designed to Work with Existing JupyterHub Deployments&lt;/h2&gt;
&lt;p&gt;Positron Server is built to integrate directly into existing JupyterHub environments, making adoption straightforward for administrators already managing Jupyter-based infrastructure.&lt;/p&gt;
&lt;p&gt;The solution is compatible with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JupyterHub deployments running JupyterLab 4&lt;/li&gt;
&lt;li&gt;Python 3.9 and later environments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Installation is provided through the &lt;a href="https://posit-dev.github.io/jupyter-positron-server/"&gt;jupyter-positron-server&lt;/a&gt; Python package, which is built on &lt;a href="https://jupyter-server-proxy.readthedocs.io/"&gt;Jupyter Server Proxy&lt;/a&gt;. For administrators who have previously configured services within JupyterHub, the setup process will feel familiar.&lt;/p&gt;
&lt;p&gt;Rather than functioning as a standalone desktop application, Positron Server extends existing JupyterHub deployments by making the Positron IDE available as another launch option within the environment.&lt;/p&gt;
&lt;h2 id="free-educational-licensing-for-teaching"&gt;Free Educational Licensing for Teaching&lt;/h2&gt;
&lt;p&gt;Academic institutions using Positron for instructional purposes are eligible for a free teaching license. Under this license, access can be provided to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Currently enrolled students&lt;/li&gt;
&lt;li&gt;Course participants&lt;/li&gt;
&lt;li&gt;Faculty and staff involved in delivering educational programs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This licensing model enables institutions to incorporate Positron into coursework without additional software costs, helping educators provide professional-grade tools to learners.&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;Institutions interested in offering Positron through JupyterHub can get started in three simple steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Review the eligibility requirements outlined in the &lt;a href="https://positron.posit.co/licensing.html#positron-education-license-rider"&gt;Positron Education License Rider&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://positron.posit.co/education.html#applying-for-a-teaching-license"&gt;Contact Posit&lt;/a&gt; to request a free teaching license.&lt;/li&gt;
&lt;li&gt;Follow the &lt;a href="https://posit-dev.github.io/jupyter-positron-server/"&gt;jupyter-positron-server&lt;/a&gt; installation and configuration documentation to deploy Positron within your JupyterHub environment.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="supporting-the-next-generation-of-data-scientists"&gt;Supporting the Next Generation of Data Scientists&lt;/h2&gt;
&lt;p&gt;As data science and computational research continue to grow across disciplines, educational institutions are looking for ways to provide students with professional tools that are easy to access and manage. By bringing Positron directly into JupyterHub, universities can deliver a modern, scalable development environment that supports both teaching and learning while minimizing setup complexity.&lt;/p&gt;
&lt;p&gt;Whether students are writing Python code, analyzing data in R, or exploring advanced development workflows, Positron Server helps create a seamless experience from the first day of class through more advanced coursework and research projects.&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
</content><category term="education"/><category term="JupyterHub"/></entry><entry><title>Becoming the new JupyterHub and Jupyter Book community manager</title><link href="https://blog.jupyter.org/posts/2026/becoming-the-new-jupyterhub-and-jupyter-book-community/" rel="alternate"/><published>2026-06-15T07:01:00+00:00</published><updated>2026-06-15T07:01:00+00:00</updated><author><name>Serena Bonaretti</name></author><id>tag:blog.jupyter.org,2026-06-15:/posts/2026/becoming-the-new-jupyterhub-and-jupyter-book-community/</id><summary type="html">&lt;p&gt;There are moments in life when things, simply, converge. You work and study, study and work, and then, simply, it happens. It starts one day when somebody tells you “there is this new thing called Jupyter Notebook, you should give it a try!”. So you install it, play around with it.&lt;/p&gt;</summary><content type="html">&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2026/becoming-the-new-jupyterhub-and-jupyter-book-community/images/001-1_FO2axICPqqSETF34ZMoaBw.jpeg" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;There are moments in life when things, simply, converge. You work and study, study and work, and then, simply, it happens. It starts one day when somebody tells you “there is this new thing called Jupyter Notebook, you should give it a try!”. So you install it, play around with it. It works like a charm. It’s easy, fast, nearly playful. It’s beautiful–and if you grow up in Italy, beauty always matters. Then, you have the urge to tell others about it. You organize a workshop at a conference in musculoskeletal image analysis and introduce marvelous novel tools for computational research: “You know? Nowadays we can do open science easily because somebody has created Jupyter Notebook, Binder, new Python libraries!” And then, together with some friends, you write a proposal for a &lt;a href="https://blog.jupyter.org/posts/2022/report-on-the-jupyter-community-workshop/"&gt;Jupyter Community Workshop&lt;/a&gt;, and–unbelievable!–you get it. Initially, you think you are just organizing a workshop. But somehow, the number of people interested becomes larger and larger, and you find yourself co-founding and coordinating what is now the Open and Reproducible Musculoskeletal Imaging Research (&lt;a href="https://www.ormir.org"&gt;ORMIR&lt;/a&gt;) Community. In ORMIR’s Python packages, the examples are in Jupyter Notebook, the documentation is in Jupyter Book. Sooner or later, we will have our JupyterHubs too; it’s just a matter of time. In parallel, life gives you some professional challenges. So you start teaching Python online, one-to-one. You look for material that fits your style, but you cannot find any. So you start teaching it your way, using Jupyter Notebook in JupyterLab and it works. Students find it easy, independent of their background. The teaching material seems to work, so you transcribe it into a book entitled &lt;a href="http://www.learnpythonwithjupyter.com"&gt;Learn Python with Jupyter&lt;/a&gt;, and you make it open. At the same time, you are obsessed with keeping up to date. You go to JupyterCon, meet the people, watch their YouTube videos, participate in online meetings. And then, there is a &lt;a href="https://blog.jupyter.org/posts/2026/call-for-applications-community-manager-for-jupyterhub/"&gt;job posting&lt;/a&gt; for a community manager. And you are like: “Nah, they will never hire me”, so you set it aside. But then somebody out of the blue tells you to apply because “100% of lottery winners played!”. So you give it a chance, and here I am: my name is &lt;a href="https://sbonaretti.github.io/"&gt;Serena Bonaretti&lt;/a&gt; and I am the new JupyterHub and Jupyter Book community manager!&lt;/p&gt;
&lt;p&gt;In this new role, I am very much looking forward to working with the JupyterHub and Jupyter Book communities! I will collaborate with maintainers to understand and document projects’ priorities and define the best processes to achieve their vision. I will support contributors in finding their way into the projects and make the real-world impact that they hope to achieve. I will dialogue with users to make sure that the tools we create are useful for their work. And I will share our activities monthly and what we learn with anybody interested, so that we can all benefit from this journey!&lt;/p&gt;
&lt;p&gt;And you? How did you start using the tools of the Jupyter ecosystem? Do you work in JupyterHub? Have you ever written a Jupyter Book? Would you like to be a contributor? Are you an enthusiastic user? Write me on &lt;a href="https://discord.mystmd.org/"&gt;Discord&lt;/a&gt; (Jupyter Book/MyST) or &lt;a href="https://jupyter.zulipchat.com/#narrow/channel/469744-jupyterhub"&gt;Zulip&lt;/a&gt; (JupyterHub). The JupyterHub and Jupyter Book communities and I are looking forward to getting to know you!&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
</content><category term="community"/><category term="Jupyter Book"/><category term="JupyterHub"/></entry><entry><title>Better sharing UX with nbgitpuller and contextual error handling</title><link href="https://blog.jupyter.org/posts/2026/better-sharing-ux-with-nbgitpuller-and-contextual-error/" rel="alternate"/><published>2026-04-09T15:02:00+00:00</published><updated>2026-04-09T15:02:00+00:00</updated><author><name>Jenny Wong</name></author><id>tag:blog.jupyter.org,2026-04-09:/posts/2026/better-sharing-ux-with-nbgitpuller-and-contextual-error/</id><summary type="html">&lt;p&gt;nbgitpuller now has improved UX context-aware error handling. Update to version 1.3.0 and let us know what you think by opening an issue 🚀&lt;/p&gt;</summary><content type="html">&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2026/better-sharing-ux-with-nbgitpuller-and-contextual-error/images/001-1_d1wtukpXH7983Z0nCKv33Q.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/jupyterhub/nbgitpuller"&gt;nbgitpuller&lt;/a&gt; now has improved UX context-aware error handling. Update to &lt;a href="https://pypi.org/project/nbgitpuller/1.3.0/"&gt;version 1.3.0&lt;/a&gt; and let us know what you think by opening an &lt;a href="https://github.com/jupyterhub/nbgitpuller/issues"&gt;issue&lt;/a&gt; 🚀&lt;/p&gt;
&lt;h2 id="what-is-nbgitpuller"&gt;What is nbgitpuller?&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/jupyterhub/nbgitpuller"&gt;nbgitpuller&lt;/a&gt; lets you distribute content to a Jupyter user via the click of a button! This allows your users to focus on the content without needing to understand git or other version control machinery.&lt;/p&gt;
&lt;p&gt;nbgitpuller provides &lt;a href="https://nbgitpuller.readthedocs.io/en/latest/topic/automatic-merging.html"&gt;automatic, opinionated conflict resolution&lt;/a&gt; by using git under the hood. It is commonly used to distribute content to multiple users of a JupyterHub, though it works just fine on an individual person’s computer, if they have Jupyter installed.&lt;/p&gt;
&lt;p&gt;Here’s an example of nbgitpuller in action:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The author uses the &lt;a href="https://nbgitpuller.readthedocs.io/en/latest/link.html"&gt;nbgitpuller link generator&lt;/a&gt; to create a link.&lt;/p&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2026/better-sharing-ux-with-nbgitpuller-and-contextual-error/images/002-0_2M4f_Hh6iyGP7VCo.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The consumer clicks the link, and the content is pulled into a live Jupyter session.&lt;/p&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2026/better-sharing-ux-with-nbgitpuller-and-contextual-error/images/003-0_J_A7MbZ2JI5hZh7n.mp4" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Example use cases for sharing with nbgitpuller include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Interactive demos&lt;/li&gt;
&lt;li&gt;Workshop and training scenarios&lt;/li&gt;
&lt;li&gt;University exams&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and many more!&lt;/p&gt;
&lt;h2 id="how-does-nbgitpuller-work"&gt;How does nbgitpuller work?&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;nbgitpuller&lt;/code&gt; package is installed in the compute environment. The compute environment now has a &lt;code&gt;/git-pull&lt;/code&gt; endpoint URL that can understand where to pull content from using URL parameters. Syncing content critically depends on &lt;code&gt;git&lt;/code&gt; operations to &lt;code&gt;fetch&lt;/code&gt;, &lt;code&gt;checkout&lt;/code&gt;, &lt;code&gt;clone&lt;/code&gt;, &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;commit&lt;/code&gt;, etc.&lt;/p&gt;
&lt;h2 id="when-it-goes-wrong"&gt;When it goes wrong&lt;/h2&gt;
&lt;p&gt;Based on the data sent through by the kind folks running the Berkeley DataHub, there were 2163 logs available, of which:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;983 (45%) were ‘merge’ conflicts&lt;/li&gt;
&lt;li&gt;493 (23%) were ‘fetch’ errors&lt;/li&gt;
&lt;li&gt;467 (22%) were ‘ls-remote’ errors&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img alt="Bar chart showing the most common errors users faced." src="https://blog.jupyter.org/posts/2026/better-sharing-ux-with-nbgitpuller-and-contextual-error/images/004-1_v1NGeWyH5Frl9QDJ2qed0Q.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Bar chart showing the most common errors users faced.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The remaining errors (10%) were mostly ‘checkout’ errors. This represents the most &lt;strong&gt;frequent&lt;/strong&gt; errors as seen by students.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Bar chart showing the most unique errors link authors made." src="https://blog.jupyter.org/posts/2026/better-sharing-ux-with-nbgitpuller-and-contextual-error/images/005-1_6sYjI1QPnc_yz6IiIw442g.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Bar chart showing the most unique errors link authors made.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In the same set of logs, there were 172 &lt;strong&gt;unique&lt;/strong&gt; errors: most ‘ls-remote’ errors come from mistakes in the content repo URL. This represents the most uniquely common errors made by instructors.&lt;/p&gt;
&lt;h2 id="merge-conflicts"&gt;Merge conflicts&lt;/h2&gt;
&lt;p&gt;If the link author changes content after the consumer clicks a link, then &lt;code&gt;nbgitpuller&lt;/code&gt; needs to sync updates for the consumer on subsequent link clicks. The &lt;code&gt;nbgitpuller&lt;/code&gt; merging strategy makes opinionated choices so that the link consumer &lt;em&gt;never&lt;/em&gt; has to interact with git, and will always preserve the consumer’s working changes.&lt;/p&gt;
&lt;p&gt;Things can go wrong when&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consumers can diverge the git history if they perform a git commit&lt;/li&gt;
&lt;li&gt;Authors can diverge the git history if they perform force push commits&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="error-ux-old"&gt;Error UX (old)&lt;/h2&gt;
&lt;figure&gt;
&lt;img alt="Old UX for merge errors." src="https://blog.jupyter.org/posts/2026/better-sharing-ux-with-nbgitpuller-and-contextual-error/images/006-1_prhJ0nFlArAhfFwFFZbbLA.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Old UX for merge errors.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Problems with the old UX include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a scary terminal&lt;/li&gt;
&lt;li&gt;difficulty for the user to figure out what went wrong&lt;/li&gt;
&lt;li&gt;no suggestion for the user to fix the problem or a signpost to continue to the compute platform&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="error-ux-new"&gt;Error UX (new)&lt;/h2&gt;
&lt;figure&gt;
&lt;img alt="New UX for merge errors." src="https://blog.jupyter.org/posts/2026/better-sharing-ux-with-nbgitpuller-and-contextual-error/images/007-1_iE8c5G51r3qL8ITBFiOZKg.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;New UX for merge errors.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;New improvements to the UX include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The terminal is closed by default, but you can optionally toggle it open&lt;/li&gt;
&lt;li&gt;There is a copy to clipboard button to easily share the error log from the terminal&lt;/li&gt;
&lt;li&gt;A more user-friendly and context-aware helper message is displayed&lt;/li&gt;
&lt;li&gt;A link to the general documentation for reference&lt;/li&gt;
&lt;li&gt;A ‘Proceed without syncing’ button takes the user to the compute platform without making any changes&lt;/li&gt;
&lt;li&gt;In the case of merge errors, an extra &lt;strong&gt;Backup and resync&lt;/strong&gt; button option is presented&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="learn-more"&gt;Learn more&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nbgitpuller.readthedocs.io/en/latest/"&gt;nbgitpuller documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
&lt;h2 id="acknowledgements"&gt;Acknowledgements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.berkeley.edu/"&gt;UC Berkeley&lt;/a&gt; and the &lt;a href="https://www.cloudbank.org/training/access-cloudbank-classroom"&gt;CloudBank Classroom&lt;/a&gt; project&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cal-icor.org/"&gt;CAL ICOR&lt;/a&gt; for co-funding this development work&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ericvd-ucb"&gt;Eric Van Dusen&lt;/a&gt; and &lt;a href="https://github.com/sean-morris"&gt;Sean Morris&lt;/a&gt; for championing this work&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/balajialg"&gt;Balaji Alwar&lt;/a&gt; for providing the error data and sharing feedback&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nthiery"&gt;Nicolas M. Thiéry&lt;/a&gt; for feedback on the UX design&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cmarmo"&gt;cmarmo&lt;/a&gt; for contributing the ‘Backup and resync button’&lt;/li&gt;
&lt;/ul&gt;
</content><category term="education"/><category term="JupyterHub"/></entry><entry><title>Call for applications: Community Manager for JupyterHub and Jupyter Book</title><link href="https://blog.jupyter.org/posts/2026/call-for-applications-community-manager-for-jupyterhub/" rel="alternate"/><published>2026-03-05T16:44:00+00:00</published><updated>2026-03-05T19:07:00+00:00</updated><author><name>Kirstie Whitaker</name></author><id>tag:blog.jupyter.org,2026-03-05:/posts/2026/call-for-applications-community-manager-for-jupyterhub/</id><summary type="html">&lt;p&gt;The JupyterHub and Jupyter Book communities are hiring a community manager.&lt;/p&gt;</summary><content type="html">&lt;p&gt;The &lt;a href="https://jupyter.org/hub"&gt;JupyterHub&lt;/a&gt; and &lt;a href="https://jupyterbook.org"&gt;Jupyter Book&lt;/a&gt; communities are hiring a &lt;strong&gt;community manager&lt;/strong&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="a cartoon of people working together. there are a group in the center and then spokes of people working in different contexts on different focus areas, some are alone but others are working in smaller groups, all part of the whole collaboration." src="https://blog.jupyter.org/posts/2026/call-for-applications-community-manager-for-jupyterhub/images/001-1__jfvloGZbtvcYdoZ0N6orA.jpeg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Join our community and support us all to grow, nurture, and build things together. Credit: The Turing Way and Scriberia, used under a CC-BY license &lt;a href="https://doi.org/10.5281/zenodo.3332808"&gt;https://doi.org/10.5281/zenodo.3332808&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In JupyterHub, we are democratizing access to interactive computing environments to allow everyone, no matter where they are, to explore data, develop code, and advance knowledge without barriers. In Jupyter Book, we are building the next generation of open, community-driven technical publication tooling, leveraging the &lt;a href="https://mystmd.org/"&gt;MyST document engine&lt;/a&gt; to create modular, reusable, and reproducible computational narratives.&lt;/p&gt;
&lt;p&gt;We are excited to fund dedicated time for someone — maybe you! — to join these teams.&lt;/p&gt;
&lt;p&gt;The community manager will be responsible for identifying and developing activities and communication pathways that align maintainer and contributor actions with the goals of each project, and that build bridges across the Jupyter ecosystem.&lt;/p&gt;
&lt;p&gt;You can read more about our motivation for this role in the &lt;a href="https://github.com/jupyter-governance/funding-proposals/issues/6"&gt;proposal&lt;/a&gt;, part of the Jupyter Foundation’s &lt;a href="https://jupyterfoundation.org/community-funding-proposals"&gt;Community Funding&lt;/a&gt; initiative. We particularly encourage applicants to review the section “&lt;em&gt;Impact Metrics: How do we define success?&lt;/em&gt;”&lt;/p&gt;
&lt;p&gt;In this blog post we have outlined the community manager’s &lt;strong&gt;responsibilities&lt;/strong&gt;, their &lt;strong&gt;preferred expertise&lt;/strong&gt;, and &lt;strong&gt;how to apply.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is a contract role, funded at $90,000 to be spent by the end of April 2027.&lt;/strong&gt; The community manager will be engaged as a contractor of the Linux Foundation and will follow the standard Linux Foundation contractor onboarding process.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The deadline to apply is 29 March 2026.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="responsibilities"&gt;Responsibilities&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Strategic alignment and contributor guidance&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Collaborate with the maintainer teams from both projects to understand, document, and broadcast each project’s priorities to their communities.&lt;/li&gt;
&lt;li&gt;Actively connect contributors to open issues and workstreams that align with the respective project’s goals, and redirect well-intentioned contributions that are not aligned with the project’s currently prioritized efforts.&lt;/li&gt;
&lt;li&gt;Efficiently connect contributors with maintainers to provide them the guidance and review needed to make efficient progress, managing workload on both sides of the mentorship pair.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Contributor growth and leadership development&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Design, visualize, and manage a clear contributor journey, including identifying requisite skills and project context knowledge, for each community.&lt;/li&gt;
&lt;li&gt;Identify engaged community members and create pathways for them to take on more responsibility, such as triaging issues, reviewing pull requests, or mentoring others within their project of interest.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Fostering knowledge sharing and collaboration&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Identify and create opportunities for the community of each project to share information, best practices, and technical knowledge, while respecting their distinct roadmaps.&lt;/li&gt;
&lt;li&gt;Facilitate cross-community events, such as running “collaboration cafes” for both JupyterHub and JupyterBook, and strategically shape them into meetings that provide value and foster connection for both projects.&lt;/li&gt;
&lt;li&gt;Develop re-usable templates for explaining contributor pathways, such as onboarding documentation, skills maps/matrices for progression into contribution and maintenance roles, and collaboration cafe guides.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Learn in the open&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensure all materials are publicly available and discoverable, including progress against our community health metrics described below.&lt;/li&gt;
&lt;li&gt;Promote these learnings across the Jupyter community including within the Zulip channel, at regular community calls, and by “visiting” other sub-projects (at synchronous meetings or in asynchronous discussion spaces) to discuss community management efforts as requested.&lt;/li&gt;
&lt;li&gt;Join the &lt;a href="https://jupyter.org/governance/communitybuildingworkinggroup/"&gt;Jupyter Community Building Working Group&lt;/a&gt; and be an active member throughout their paid time on the project.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="preferred-expertise"&gt;Preferred expertise&lt;/h2&gt;
&lt;p&gt;We have not marked any of the expertise categories listed here as &lt;em&gt;required&lt;/em&gt;. We recognize that we are looking for a unicorn, and they are curiously hard to find! &lt;strong&gt;If you do not have expertise across all of these categories we encourage you to apply.&lt;/strong&gt; We are looking forward to getting to know candidates better, including where they have identified opportunities for career and skill development as part of the JupyterHub and Jupyter Book teams.&lt;/p&gt;
&lt;p&gt;Our assessment pathway is included as part of this list to guide applicants in curating their strongest application. If you are uncertain how to answer any of the questions and/or prompts, please ask in our &lt;a href="https://jupyter.zulipchat.com/#narrow/channel/469744-jupyterhub"&gt;Jupyter Hub Zulip channel&lt;/a&gt; or email Kirstie Whitaker directly at &lt;a href="mailto:kirstie.whitaker@berkeley.edu"&gt;kirstie.whitaker@berkeley.edu&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Track record of contributions to open source projects.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Assessment: Cover letter &amp;amp; links&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Understanding of multi-stakeholder, community governed open source community dynamics.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Assessment: Interview question. Describe two situations — one featuring a success and one a failure — where you have sought to align diverse stakeholders around a common goal. For both, share what you learned from the experiences.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Understanding of the challenges that Jupyter Hub and Jupyter Book are designed to solve (or reduce) in the world.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Assessment: Interview question. Describe two deployments — one each of Jupyter Hub and Jupyter Book — that each meet a need in either education, research or technical development. You do not need to have run these deployments yourself.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical skills in Python and/or TypeScript.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Assessment: Cover letter &amp;amp; links&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Track record of identifying and completing tasks in the presence of significant uncertainty.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Assessment: Cover letter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Ability to work effectively with two distinct and diverse teams whose community members are geographically distributed with significant time zone differences.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Assessment: Cover letter. All instructions from this recruitment call followed, the letter is clearly and concisely written, includes concrete examples, and publicly accessible links where appropriate.&lt;/li&gt;
&lt;li&gt;Assessment: Interview question. Given your knowledge of Jupyter Hub and Jupyter Book, and your previous experience, how will you know if you are working effectively within these two communities?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Ability to ask for help and self manage time allocations and tasks.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Assessment: Interview question. Which aspects of this role do you think will be hard for you? Which aspects will be easy (or easier) for you? Where do you expect to ask for help and/or support in the role?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-to-apply"&gt;How to apply&lt;/h2&gt;
&lt;p&gt;Submit a cover letter and resume through this Google Form: &lt;a href="https://forms.gle/Qw6ddyJ8rzZY5vQm6"&gt;https://forms.gle/Qw6ddyJ8rzZY5vQm6&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Please include:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Your motivation to apply for this role.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Links to up to 3 publicly available GitHub repositories that highlight engagement in issues, pull requests, community discussions (or equivalent conversations on alternative git forge platforms).&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you don’t have publicly available links, provide a letter from a team member from a private initiative who can endorse these collaboration skills.&lt;/li&gt;
&lt;li&gt;If you can not meet this requirement, please note that in your application.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Links to up to 3 examples of code you have written in Python and/or TypeScript.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you don’t have publicly available links, provide a letter from a team member on a private initiative endorsing these development skills.&lt;/li&gt;
&lt;li&gt;If you can not meet this requirement, please note that in your application.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;A description of a previous role (paid or volunteer) where you have identified and delivered outcomes in the presence of uncertainty.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Include links to task documentation (issue / PR / report) if publicly available.&lt;/li&gt;
&lt;li&gt;If you can not meet this requirement, please note that in your application.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-to-expect"&gt;What to expect&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;We’ll accept applications from now through 29 March, 2026.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Once applications are in, here’s our process:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Resume and cover letter review:&lt;/strong&gt; The recruitment panel will review all applications and invite up to 5 applicants for an interview on zoom at a time that is convenient for the applicant and the panel members.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interview:&lt;/strong&gt; The recruitment panel will meet with applicants for 30 minutes over Zoom. They will ask the same questions of every applicant.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Panel discussion &amp;amp; alignment:&lt;/strong&gt; The recruitment panel will discuss interview outcomes and align on a decision.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Offer:&lt;/strong&gt; We expect to communicate a final decision to all applicants by 30 April, 2026.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Timeline&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;29 March 2026, &lt;a href="https://en.wikipedia.org/wiki/Anywhere_on_Earth"&gt;AoE&lt;/a&gt;: Deadline for resume and cover letter applications.&lt;/li&gt;
&lt;li&gt;Before 5 April 2026: Invite up to 5 applicants to interview.&lt;/li&gt;
&lt;li&gt;8 April — 17 April 2026: Interviews conducted over Zoom.&lt;/li&gt;
&lt;li&gt;Before 11 May 2026: Communicate final decision to all applicants.&lt;/li&gt;
&lt;li&gt;May 2026: Post holder coordinates a contract with the Linux Foundation, following their standard onboarding process.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
&lt;h2 id="acknowledgements"&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;This job description was co-created by April Johnson, Yuvi, and Kirstie Whitaker, with guidance from Chris Holdgraf, Min Ragan-Kelley, Raniere Silva, and Stéfan van der Walt, along with community input at the JupyterHub and Jupyter Book collaboration cafes.&lt;/p&gt;
</content><category term="community"/><category term="Jupyter Book"/><category term="JupyterHub"/></entry><entry><title>Scaling “Maintainer Intuition” with Pull Request Triage Boards</title><link href="https://blog.jupyter.org/posts/2025/scaling-maintainer-intuition-with-pull-request-triage/" rel="alternate"/><published>2025-11-16T21:22:00+00:00</published><updated>2025-11-16T21:22:00+00:00</updated><author><name>Yuvi Panda</name></author><id>tag:blog.jupyter.org,2025-11-16:/posts/2025/scaling-maintainer-intuition-with-pull-request-triage/</id><summary type="html">&lt;p&gt;When I helped start 2i2c.org, one of my goals for the non-profit was to experiment with new and different ways of supporting the Jupyter ecosystem’s long term health.&lt;/p&gt;</summary><content type="html">&lt;p&gt;When I helped start &lt;a href="https://2i2c.org"&gt;2i2c.org&lt;/a&gt;, one of my goals for the non-profit was to experiment with new and different ways of supporting the Jupyter ecosystem’s long term health. As part of that, we have identified how &lt;a href="https://2i2c.org/blog/2025/good-citizen/"&gt;foundational contributions are very important (and distinct from directed contributions)&lt;/a&gt;, and have been experimenting with &lt;a href="https://2i2c.org/blog/2025/foundational-contributions/"&gt;new ways to make foundational contributions&lt;/a&gt; in sustainable and structured ways.&lt;/p&gt;
&lt;p&gt;One such way was via systematically doing code reviews for Pull Requests from non-maintainers in the JupyterHub ecosystem. Reviewing PRs is a critical way that maintainers keep an open source project moving forward, but identifying PRs that can productively be merged is hard. This is a post describing our system for scaling this in our team. Each 2 week sprint, we:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Looked at all open PRs in the JupyterHub org who were not maintainers&lt;/li&gt;
&lt;li&gt;Picked a PR that I deemed was reviewable and ideally mergeable within this time window&lt;/li&gt;
&lt;li&gt;Have an engineer on the team pick up that PR, and try to get it to close&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/2i2c-org/infrastructure/issues/5058"&gt;Report back&lt;/a&gt; on what we have learnt, so we can iterate on our process&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We managed to do this for a majority of sprints over the last roughly 12 months! One key bottleneck we identified in the process was Step 2. In particular, I was relying on my &lt;em&gt;maintainer intuition&lt;/em&gt; to pick a single PR that I &lt;em&gt;believe&lt;/em&gt; can be merged, so others in the team can do review work. I started exploring &lt;em&gt;what&lt;/em&gt; this intuition is, and if it can be scaled.&lt;/p&gt;
&lt;h2 id="what-is-this-maintainer-intuition"&gt;What is this maintainer intuition?&lt;/h2&gt;
&lt;p&gt;How did I pick a PR from a long list of open PRs? Observing my own behavior a few times, I noticed I was looking for:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;PRs that aren’t too &lt;em&gt;big&lt;/em&gt;, and are &lt;strong&gt;a reasonable size&lt;/strong&gt; that can be merged within a 2 week window&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CI tests passing&lt;/strong&gt;, so at least our automated checks haven’t caught any issues with it&lt;/li&gt;
&lt;li&gt;Features or bug fixes that I believe &lt;strong&gt;add value to the project&lt;/strong&gt; and move us in the right direction towards being able to support our users as they need (this is the hardest!)&lt;/li&gt;
&lt;li&gt;If the author of the PR is a &lt;strong&gt;newish contributor&lt;/strong&gt;, as I want to encourage them to stick around by being responsive to their gift. All PRs are gifts that we may or may not choose to accept, but should do so with grace.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How long ago the PR was opened&lt;/strong&gt;. There is such a big difference between a response to your PR 2 days after you make it vs 2 months vs 2 years. I prioritized newer PRs.&lt;/li&gt;
&lt;li&gt;What &lt;strong&gt;kind of contribution&lt;/strong&gt; is it primarily? Different engineers on our team have different skillsets (JS, Python, etc) and I wanted to match the PR to what the engineer preferred code reviewing.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While (3) is hard to scale, everything else seemed like something we could build systems for that let others follow a process, thus removing myself as a bottleneck. I experimented with some GitHub issue filters and project automations, and after finding them lacking, built out a brand new open source project to do this: &lt;a href="https://github.com/jupyter/pr-triage-board-bot"&gt;pr-triage-board-bot&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id="pr-triage-github-boards"&gt;PR Triage GitHub Boards&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/jupyter/pr-triage-board-bot"&gt;pr-triage-board-bot&lt;/a&gt; automatically maintains PR Triage Boards for a Github organization. You can check out the current boards to get a sense of how it looks: &lt;a href="https://github.com/orgs/jupyterhub/projects/4"&gt;JupyterHub&lt;/a&gt;, &lt;a href="https://github.com/orgs/jupyterlab/projects/11"&gt;JupyterLab&lt;/a&gt;, and &lt;a href="https://github.com/orgs/geojupyter/projects/3"&gt;GeoJupyter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For each PR Triage Board, the bot will:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add all open, ready for review PRs&lt;/li&gt;
&lt;li&gt;Remove all closed or draft PRs&lt;/li&gt;
&lt;li&gt;Annotate each PR with additional deterministic project fields that allow for sorting and filtering in the project board. To start with, it populates the following fields:
&lt;ol&gt;
&lt;li&gt;Author kind (Maintainer, Seasoned Contributor, First Time Contributor, Bot)&lt;/li&gt;
&lt;li&gt;Size (Number of lines touched)&lt;/li&gt;
&lt;li&gt;Date it was opened&lt;/li&gt;
&lt;li&gt;If a maintainer has already interacted with the PR (One, Many, None)&lt;/li&gt;
&lt;li&gt;Are there merge conflicts?&lt;/li&gt;
&lt;li&gt;What kind of files were mostly changed? (Python, JS, Docs)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Keep this up to date by automatically running every hour via GitHub actions&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once these project fields are populated automatically, maintainers can create different Project Views for themselves to help with different workflows via filters and sorting. For example, &lt;a href="https://github.com/orgs/jupyterhub/projects/4"&gt;the JupyterHub board&lt;/a&gt; contains the following views:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;PRs split by author kind, sorted by newness and size so we can try to respond to PRs from new users as early as possible&lt;/li&gt;
&lt;li&gt;PRs that have not had a single maintainer interaction on them, so we can acknowledge people’s contributions to us even if we can’t fully review it at the moment&lt;/li&gt;
&lt;li&gt;Bot PRs with all tests passing and no merge conflicts, so we can more easily stay on top of automated updates&lt;/li&gt;
&lt;li&gt;PRs that have been approved by a maintainer but not merged yet, as sometimes a maintainer wants to give others time to object but needs to go back and hit merge.&lt;/li&gt;
&lt;li&gt;PRs that are primarily updating documentation, as the review process for this can be different&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For our original purpose of getting more people to do code review, this board has served well — we can roughly say ‘Pick a PR that looks good to you from the top of the “First Time Contributor” or “Seasoned Contributor” list’, and that relieves me from being the bottleneck quite a bit. Other maintainers are also finding a lot of value in this board. For example, if you only have 15 min, you can probably get a clean bot PR reviewed and merged. Or look for PRs that haven’t been acknowledged by a maintainer and engage with them. Our next step is to help run structured social experiments, where we try to establish specific ceremonies in the open source ecosystem to get specific lists of open PRs (such as “PRs with no maintainer engagement, or PRs older than 2y”) down to zero. Stay tuned to hear more :)&lt;/p&gt;
&lt;p&gt;We are essentially using GitHub Project Fields as a database, adding additional fields that are very valuable to maintainers but not available in GitHub by default. While ideally these would be contributed by us directly into GitHub, only Microsoft has control over what gets added to the product. So we find interesting workarounds like this to accomplish our goals :)&lt;/p&gt;
&lt;h2 id="successful-adoption"&gt;Successful Adoption&lt;/h2&gt;
&lt;p&gt;I was just playing with this, and Raniere from the JupyterHub team spotted it and &lt;a href="https://jupyter.zulipchat.com/#narrow/channel/469744-jupyterhub/topic/.22PR.20triage.20.28experimental.29.22.20project.20on.20GitHub/with/536668935"&gt;asked about it&lt;/a&gt; on Zulip. &lt;a href="https://jasongrout.org/"&gt;Jason Grout&lt;/a&gt; from the JupyterLab team was also super interested, and with contributions from him, the bot quickly got adopted by the JupyterLab GitHub org as well. We cleaned this up a bit more, and found adoption within the GeoJupyter project too with help from &lt;a href="https://mfisher87.github.io/"&gt;Matt Fisher&lt;/a&gt;. As with everything we do at 2i2c, I had tried to design this to be widely useful to many orgs and maintainers rather than just us, and looks like I have wildly succeeded :)&lt;/p&gt;
&lt;p&gt;I am happy to announce today that 2i2c is officially donating pr-triage-board-bot to Project Jupyter! I will still continue to contribute to maintaining the project, and welcome contributions from everyone else too!&lt;/p&gt;
&lt;p&gt;If this looks useful to your open source project, consider adopting it by &lt;a href="https://github.com/jupyter/pr-triage-board-bot?tab=readme-ov-file#set-up"&gt;following these instructions&lt;/a&gt;. The project is still fairly new, so if you run into issues please let us know on the &lt;a href="https://jupyter.zulipchat.com/"&gt;Project Jupyter Zulip chat&lt;/a&gt; or by &lt;a href="https://github.com/jupyter/pr-triage-board-bot/issues"&gt;opening an issue&lt;/a&gt;.&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
</content><category term="community"/><category term="GitHub"/><category term="JupyterHub"/></entry><entry><title>Simplifying and speeding up Binder builds with BuildKit</title><link href="https://blog.jupyter.org/posts/2025/simplifying-and-speeding-up-binder-builds-with-buildkit/" rel="alternate"/><published>2025-03-03T14:05:00+00:00</published><updated>2025-03-03T14:05:00+00:00</updated><author><name>Chris Holdgraf</name></author><id>tag:blog.jupyter.org,2025-03-03:/posts/2025/simplifying-and-speeding-up-binder-builds-with-buildkit/</id><summary type="html">&lt;p&gt;The Binder Project allows users to build reproducible, sharable environments for interactive computing. To accomplish this, Binder uses a tool called repo2docker to generate an executable Docker image using the Reproducible Execution Environment Specification.&lt;/p&gt;</summary><content type="html">&lt;p&gt;The &lt;a href="http://mybinder.org"&gt;Binder Project&lt;/a&gt; allows users to build reproducible, sharable environments for interactive computing. To accomplish this, Binder uses a tool called &lt;a href="https://repo2docker.readthedocs.io/"&gt;repo2docker&lt;/a&gt; to generate an executable Docker image using the &lt;a href="https://repo2docker.readthedocs.io/en/latest/specification.html"&gt;Reproducible Execution Environment Specification&lt;/a&gt;.&lt;/p&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2025/simplifying-and-speeding-up-binder-builds-with-buildkit/images/001-1_NOEeFGGHdpGZMHSq5ykl9A.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;The first time a repository is launched on Binder, repo2docker must build the reproducible environment for it. This process can take a long time because of all the dependencies that need to be installed and turned into the image. As a result, Binder launches can feel slow and clunky, which is a poor UX for workflows that are designed around quick interactive sessions.&lt;/p&gt;
&lt;p&gt;repo2docker was built several years ago, and followed patterns that were commonplace at the time. However, in the past few years the Docker community has made significant advances in optimizing the image building process. One-such improvement is the creation of &lt;a href="https://docs.docker.com/build/buildkit/"&gt;BuildKit&lt;/a&gt;, a replacement for Docker’s historical build system that is much more sophisticated. However, repo2docker hasn’t leveraged these improvements because it was still using the original Docker Build system.&lt;/p&gt;
&lt;p&gt;So, we’ve decided to spend a few cycles modernizing repo2docker’s image building logic by using the more modern &lt;a href="https://docs.docker.com/build/buildkit/"&gt;BuildKit API&lt;/a&gt; (via &lt;code&gt;docker buildx build&lt;/code&gt;). This allows for optimizations like build parallelization, better build caching, and supporting some &lt;code&gt;Dockerfile&lt;/code&gt; features that Binder didn’t support earlier (particularly, &lt;code&gt;COPY --chown&lt;/code&gt;). It also lays a foundation for significantly simplifying the repo2docker build infrastructure and leveraging more of BuildKit’s parallelization functionality. For example, we’d like to &lt;a href="https://docs.docker.com/build/builders/drivers/kubernetes/"&gt;leverage BuildKit’s Kubernetes driver&lt;/a&gt; which distributes builds much more efficiently and in parallel.&lt;/p&gt;
&lt;p&gt;Authors of Binder repositories won’t need to take any action&lt;sup class="footnote-ref"&gt;&lt;a href="#fn1" id="fnref1"&gt;[1]&lt;/a&gt;&lt;/sup&gt;, and they’ll simply notice that mybinder.org (and any other community-run BinderHub instance) will be a bit snappier at building images.&lt;/p&gt;
&lt;p&gt;If you’d like to learn more about the changes that enabled this, &lt;a href="https://github.com/jupyterhub/mybinder.org-deploy/pull/3225"&gt;check out this mybinder.org pull request&lt;/a&gt; which has links to the repo2docker pull requests that added this functionality. We’re excited keep improving Binder, and are hopeful that this makes the experience of using mybinder.org and community Binders a little bit better.&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
&lt;h2 id="authors-and-acknowledgements"&gt;Authors and acknowledgements&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://github.com/yuvipanda"&gt;Yuvi Panda&lt;/a&gt; is a co-founder and the Technical Lead at &lt;a href="http://2i2c.org"&gt;2i2c&lt;/a&gt;. He is passionate about building participatory open infrastructure for scientific &amp;amp; educational use cases. He is a Project Jupyter team member primarily focused on infrastructure related projects (JupyterHub, Binder, etc). He also wrote most of the code for this &lt;code&gt;docker buildx&lt;/code&gt; transition, and shepherded it through to deployment on mybinder.org as well. He is ex-Wikimedia and ex-GNOME. Let’s eliminate accidental complexities wherever we find them.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://chrisholdgraf.com"&gt;Chris Holdgraf&lt;/a&gt; is a co-founder and the Executive Director of &lt;a href="http://2i2c.org"&gt;2i2c&lt;/a&gt;. He is on the Executive Council of Project Jupyter, and co-leads the &lt;a href="https://jupyterhub-team-compass.readthedocs.io/en/latest/team.html#jupyterhub-team"&gt;JupyterHub and Binder team&lt;/a&gt; as well as the &lt;a href="https://compass.jupyterbook.org"&gt;Jupyter Book team&lt;/a&gt;). He was previously a post-doctoral researcher in the Department of Statistics at &lt;a href="https://www.berkeley.edu/"&gt;UC Berkeley&lt;/a&gt;, and a Community Architect with the &lt;a href="https://data.berkeley.edu/"&gt;Division of Data Science&lt;/a&gt; at Berkeley. He’s interested in using open infrastructure to support interactive computing workflows in research and education.&lt;/p&gt;
&lt;p&gt;Many thanks to &lt;a href="https://github.com/minrk"&gt;@minrk&lt;/a&gt;, &lt;a href="https://github.com/manics"&gt;@manics&lt;/a&gt;, and &lt;a href="https://github.com/consideRatio"&gt;@consideRatio&lt;/a&gt; for their help reviewing and shaping this work.&lt;/p&gt;
&lt;hr class="footnotes-sep"&gt;
&lt;section class="footnotes"&gt;
&lt;ol class="footnotes-list"&gt;
&lt;li id="fn1" class="footnote-item"&gt;&lt;p&gt;Unless they were relying on undocumented implementation details of the old builder — in particular, the presence of a &lt;code&gt;/.dockerenv&lt;/code&gt; file to detect if you are running in repo2docker &lt;a href="https://github.com/scikit-learn/scikit-learn/pull/30835"&gt;scikit-learn/scikit-learn#30835&lt;/a&gt; has an example. &lt;a href="#fnref1" class="footnote-backref"&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content><category term="Binder"/><category term="cloud computing"/><category term="Docker"/><category term="JupyterHub"/><category term="repo2docker"/><category term="reproducibility"/></entry><entry><title>Join JupyterHub on Zulip chat!</title><link href="https://blog.jupyter.org/posts/2025/join-jupyterhub-on-zulip-chat/" rel="alternate"/><published>2025-02-06T16:05:00+00:00</published><updated>2025-02-06T16:05:00+00:00</updated><author><name>Sarah Gibson</name></author><id>tag:blog.jupyter.org,2025-02-06:/posts/2025/join-jupyterhub-on-zulip-chat/</id><summary type="html">&lt;p&gt;The JupyterHub team have just moved all their chat to a Zulip channel!&lt;/p&gt;</summary><content type="html">&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2025/join-jupyterhub-on-zulip-chat/images/001-1_szQUtcTU4TbmrkGrSNzBpw.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;The JupyterHub team have just moved all their chat to a &lt;a href="https://jupyter.zulipchat.com/#narrow/channel/469744-jupyterhub"&gt;Zulip channel&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://jupyter.zulipchat.com"&gt;Jupyter Zulip instance&lt;/a&gt; is a Jupyter-wide chat space allowing cross-team communication in channels, some of which can be viewed publicly without an account.&lt;/p&gt;
&lt;p&gt;For the JupyterHub team, we have found better engagement from team members and across the wider eco-system by using the Zulip instance. To that end, we recently updated all of our Gitter rooms to “invite-only” so no new members could join, and left a pinned message with a link to the JupyterHub channel on Zulip and an invite to join the conversation there. We have also updated any of our repositories that had Gitter links to point to Zulip as well.&lt;/p&gt;
&lt;p&gt;If you would like to keep in touch with the JupyterHub, we would love to hear from you over on &lt;a href="https://jupyter.zulipchat.com/#narrow/channel/469744-jupyterhub"&gt;Zulip&lt;/a&gt;!&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
</content><category term="community"/><category term="JupyterHub"/></entry><entry><title>Desktop GIS software in the cloud with JupyterHub</title><link href="https://blog.jupyter.org/posts/2023/desktop-gis-software-in-the-cloud-with-jupyterhub/" rel="alternate"/><published>2023-08-02T16:23:00+00:00</published><updated>2023-08-02T16:51:00+00:00</updated><author><name>Matt Fisher</name></author><id>tag:blog.jupyter.org,2023-08-02:/posts/2023/desktop-gis-software-in-the-cloud-with-jupyterhub/</id><summary type="html">&lt;p&gt;A QGreenland workshop success story&lt;/p&gt;
</summary><content type="html">&lt;p&gt;👋 We are Trey Stafford and Matt Fisher, co-authors of the &lt;a href="https://github.com/nsidc/qgreenland"&gt;QGreenland&lt;/a&gt; data package’s source code. This year, we had the pleasure of running a hands-on geospatial data and open science &lt;a href="http://qgreenland-workshop-2023-researcher.github.io/"&gt;QGreenland Researcher Workshop&lt;/a&gt;. It was important for attendees to participate in the workshop in a hands-on way while minimizing the negative impacts of installing software, requiring expensive personal computers, and troubleshooting unique computer configurations. We felt a &lt;a href="https://jupyter.org/hub"&gt;JupyterHub&lt;/a&gt; was a good fit for our workshop for this reason, if it could accommodate our need for running QGIS — a desktop application.&lt;/p&gt;
&lt;p&gt;In this blog post, we will introduce QGreenland, describe our experience using JupyterHub in the cloud for our workshop’s computing environment, and discuss challenges we overcame to enable our attendees to use QGIS in a cloud graphical desktop environment. Finally, we will highlight some workshop outcomes and discuss opportunities for enhancement based on new developments in the Jupyter ecosystem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In our workshop, 25–30 international learners (including from Germany, India, France, Canada, Poland, and the United States) used &lt;em&gt;QGIS&lt;/em&gt; in a &lt;em&gt;JupyterHub&lt;/em&gt;’s browser-based Linux desktop environment to collaboratively test, explore, visualize, and process Earth science data simultaneously with the same user experience they expect from using &lt;em&gt;QGIS&lt;/em&gt; on their personal computers! Better yet, getting started was as simple as logging in.&lt;/strong&gt; Our workshop was a success story not just in education, but also in open source and collaborative development, and we want to share what we learned.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="A map depicting Greenland is displayed within QGIS software running in a cloud-based desktop environment. A visualization of September 2012 Arctic sea ice concentration is overlaid." src="https://blog.jupyter.org/posts/2023/desktop-gis-software-in-the-cloud-with-jupyterhub/images/001-1_ZG76hcKdS3-4PppQ6lSnuQ.jpg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Note the browser tabs at the top of this screenshot; this is a full desktop-based GIS environment running QGreenland in the cloud!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The JupyterHub used by the QGreenland 2023 Researcher Workshop was generously provided by the &lt;a href="https://cryointhecloud.com/"&gt;NASA CryoCloud&lt;/a&gt; team, whose mission is to help researchers transition to cloud-based collaboration.&lt;/p&gt;
&lt;h2 id="about-qgreenland"&gt;About QGreenland&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://qgreenland.org/"&gt;QGreenland&lt;/a&gt; is an open-source Greenland-focused geospatial data package for &lt;a href="https://qgis.org/en/site/"&gt;QGIS&lt;/a&gt;, a community-owned graphical Geographic Information System (GIS) platform. Researchers and members of the public leverage QGreenland’s ready-to-use interdisciplinary datasets to do field planning, teach about glaciers, and much more.&lt;/p&gt;
&lt;p&gt;QGreenland’s MIT-licensed &lt;a href="https://github.com/nsidc/qgreenland/"&gt;source code&lt;/a&gt; uses community-maintained open software like &lt;a href="https://gdal.org/index.html"&gt;GDAL&lt;/a&gt; and &lt;a href="https://qgis.org/pyqgis/latest"&gt;PyQGIS&lt;/a&gt; to automate data normalization and populate the QGIS project with important information like data provenance and the order of layers in the QGIS Layers Panel. Check out &lt;a href="https://qgreenland.readthedocs.io"&gt;our documentation&lt;/a&gt; to learn more! QGreenland also has a &lt;a href="https://www.youtube.com/@qgreenland/videos"&gt;YouTube channel&lt;/a&gt; with tutorials produced by &lt;a href="https://cires.colorado.edu/outreach/programs/qgreenland"&gt;CIRES Education and Outreach&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="A map depicting Greenland is displayed within QGIS software running in a cloud-based desktop environment. Visualizations of bathymetric depth, Greenland ice sheet thickness, and Arctic sea routes are overlaid." src="https://blog.jupyter.org/posts/2023/desktop-gis-software-in-the-cloud-with-jupyterhub/images/002-0__t2MDU659mlYEvxD.jpg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Once QGIS is installed, opening QGreenland is as easy as double-clicking the included “.qgs” file. Here, a representative view of QGreenland v3 alpha in QGIS is displayed with newly updated layers: Arctic sea routes (National Geospatial Intelligence Agency), bathymetric depth (General Bathymetric Chart of the Oceans (GEBCO)), and ice thickness (IceBridge BedMachine Greenland v5) layers.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Based on user research, QGreenland has enabled:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the public to more easily access data gathered by researchers visiting Greenland: &lt;em&gt;“In Greenland, people are often asking, ‘how can we find the data the foreign scientists bring back from Greenland?’ Now we can directly utilize much of it.”&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;researchers to plan field work: &lt;em&gt;“Being able to use QGreenland at our field station was critical to our research process!”&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;educators to develop interactive lessons about Greenland and climate change: &lt;em&gt;“…using QGreenland for presentations because it is presentation quality already.”&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="qgreenlands-2023-researcher-workshop"&gt;QGreenland’s 2023 researcher workshop&lt;/h2&gt;
&lt;p&gt;One of the QGreenland team’s most important forms of direct user interaction and support is facilitating workshops. Most recently, we hosted a 3-day (total of 9 hours) virtual workshop for researchers focused on working with geospatial data in an open science framework. All of the &lt;a href="https://qgreenland-workshop-2023-researcher.github.io/content/materials.html"&gt;materials&lt;/a&gt; covered in the workshop were built &lt;a href="https://qgreenland-workshop-2023-researcher.github.io/content/built-with-open-source.html"&gt;using open-source tools&lt;/a&gt; and are MIT-licensed and &lt;a href="https://github.com/qgreenland-workshop-2023-researcher/qgreenland-workshop-2023-researcher.github.io"&gt;published on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="a-personal-computer-in-the-cloud"&gt;A “personal computer” in the cloud&lt;/h3&gt;
&lt;p&gt;We decided early on that we wanted to use JupyterHub to solve the diverse problems that come with “bring your own device” workshops. We experimented with administering our own &lt;a href="http://z2jh.jupyter.org"&gt;JupyterHub on Kubernetes&lt;/a&gt;, but the setup overhead was too high for our short workshop. CryoCloud’s JupyterHub enabled us to avoid this overhead and focus on serving our participants. Because the software that comprises CryoCloud is open-source and developed in collaboration with the communities CryoCloud serves, we could directly contribute to curating a computing environment ideal for our participants.&lt;/p&gt;
&lt;p&gt;JupyterHub is known for providing access to Jupyter Notebooks via JupyterLab, but it turns out it can also be used to host pretty much any interactive web based application! The &lt;a href="https://github.com/jupyterhub/jupyter-server-proxy/"&gt;jupyter-server-proxy&lt;/a&gt; project enables this, and there are additional packages that make running specific applications easier. &lt;a href="https://github.com/jupyterhub/jupyter-rsession-proxy"&gt;jupyter-rsession-proxy&lt;/a&gt; makes it easy to run &lt;a href="https://posit.co/download/rstudio-server/"&gt;RStudio&lt;/a&gt; inside JupyterHub, &lt;a href="https://github.com/betatim/vscode-binder/"&gt;jupyter-vscode-proxy&lt;/a&gt; allows running code-server (fully open source self-hosted version of Visual Studio Code) inside a JupyterHub, etc. Pertinent to our use case is &lt;a href="https://github.com/jupyterhub/jupyter-remote-desktop-proxy"&gt;jupyter-remote-desktop-proxy&lt;/a&gt;, which lets you run a complete Linux desktop environment inside your JupyterHub! This was critical for our workshop, as it allowed us to use QGIS — purely desktop software, not adapted for the web — from inside a web browser. Workshop participants did not need to install anything. This enabled participants to focus on the &lt;em&gt;content&lt;/em&gt; of our workshop rather than the logistics of setting up and debugging tools on their varied machines.&lt;/p&gt;
&lt;p&gt;The CryoCloud JupyterHub enabled each of our workshop participants to provision their own compute environment (JupyterLab + Linux Desktop) with all of our workshop’s dependencies pre-installed. It also set everyone on equitable footing — someone accessing the workshop on a 10 year old laptop would get the same computing resources as someone on a brand new MacBook Pro.&lt;/p&gt;
&lt;h3 id="challenges-scaling-qgreenland"&gt;Challenges scaling QGreenland&lt;/h3&gt;
&lt;p&gt;The CryoCloud JupyterHub already had &lt;em&gt;jupyter-remote-desktop-proxy&lt;/em&gt; and &lt;em&gt;QGIS&lt;/em&gt; installed, so we could validate this approach to our workshop quickly. However, to use &lt;em&gt;QGreenland&lt;/em&gt; at this scale, we needed to solve a couple of usability problems. The first issue was a user experience problem: the operating system did not have appropriate file type associations for &lt;em&gt;QGIS&lt;/em&gt;, so files like the &lt;em&gt;QGreenland&lt;/em&gt; project file would not open in &lt;em&gt;QGIS&lt;/em&gt; when double-clicked in the desktop file browser. We quickly discovered a solution and integrated it with a &lt;a href="https://github.com/CryoInTheCloud/hub-image/pull/59"&gt;simple pull request&lt;/a&gt; to the Docker image we were using.&lt;/p&gt;
&lt;p&gt;The second problem was a performance problem: QGIS would take several minutes to open QGreenland from the hub’s shared storage drive. After some investigation, it turned out this was due to us loading multiple GB of data from an NFS share! While a long term solution might involve getting QGIS to load data directly from cloud object storage (like S3), we instead decided to go a different route — provision each user a small, fast and temporary &lt;a href="https://aws.amazon.com/ebs/"&gt;Elastic Block Store&lt;/a&gt; disk. At the start of the workshop, we provided all users a small script that would copy the dataset from NFS to this faster disk once, and this drastically reduced load times from about 5 minutes to under 3 seconds! You can follow our debugging process &lt;a href="https://github.com/CryoInTheCloud/hub-image/issues/60"&gt;on this issue&lt;/a&gt;, and find the JupyterHub config used to provision these disks &lt;a href="https://github.com/2i2c-org/infrastructure/blob/5078e5b6e2115930468f910f3095a9ffd1261eb3/helm-charts/basehub/values.yaml#L616"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By overcoming these challenges, we created a smooth, intuitive, and performant computing experience for all of our participants, most of whom had never been exposed to this sort of collaborative computing environment.&lt;/p&gt;
&lt;h3 id="outcomes"&gt;Outcomes&lt;/h3&gt;
&lt;p&gt;The workshop participants engaged in small group work to complete various exercises, group discussions, and data scenarios. Each group produced Jupyter Notebooks and GitHub Discussions posts as deliverables. We created an &lt;a href="https://qgreenland-workshop-2023-researcher.github.io/outcomes/"&gt;outcomes&lt;/a&gt; webpage to summarize our participants’ accomplishments. One highlight was &lt;a href="https://github.com/orgs/qgreenland-workshop-2023-researcher/discussions/categories/fair-care"&gt;participants’ insightful commentary on FAIR &amp;amp; CARE principles&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Based on these outcomes, we consider our workshop a success. While we put in a significant amount of time creating our materials, CryoCloud’s cloud costs and our time investment in preparing computing resources were relatively small. For approximately 25 people, our cloud costs break down to roughly &lt;strong&gt;$1/person/day&lt;/strong&gt;!&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The CryoCloud JupyterHub met our workshop needs and provided a delightful experience for administrators and participants alike, and we are excited for what’s next. JupyterLab 4 and jupyter_collaboration v1.0.0, a real-time collaboration extension, were &lt;a href="https://blog.jupyter.org/posts/2023/jupyterlab-4-0-is-here/"&gt;just announced&lt;/a&gt;, and the CryoCloud team is currently working to integrate these new releases into their hub. Real-time collaboration will enable exciting cloud use cases, like small groups working together on the same notebook without a screen share, or organizers providing technical support in a live notebook. We anticipate running this workshop again. We are excited to use JupyterHub again and look forward to experimenting with these new features!&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
&lt;h2 id="acknowledgements"&gt;Acknowledgements&lt;/h2&gt;
&lt;h3 id="reviewers"&gt;Reviewers&lt;/h3&gt;
&lt;p&gt;In alphabetical order, thanks to Twila Moon, Yuvi Panda, Tasha Snow, and Alyse Thurber for their time contributing to this post!&lt;/p&gt;
&lt;h3 id="cryocloud"&gt;CryoCloud&lt;/h3&gt;
&lt;p&gt;Snow, Tasha, Millstein, Joanna, Scheick, Jessica, Sauthoff, Wilson, Leong, Wei Ji, Colliander, James, Pérez, Fernando, James Munroe, Felikson, Denis, Sutterley, Tyler, &amp;amp; Siegfried, Matthew. (2023). CryoCloud JupyterBook (2023.01.26). Zenodo.&lt;a href="https://doi.org/10.5281/zenodo.7576602"&gt;https://doi.org/10.5281/zenodo.7576602&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="2i2c"&gt;2i2c&lt;/h3&gt;
&lt;p&gt;2i2c is a non-profit organization that runs open-source &lt;a href="https://github.com/2i2c-org/infrastructure"&gt;infrastructure&lt;/a&gt; for collaborative computing, and maintains the CryoCloud JupyterHub used in this workshop. You can see the complete configuration of this JupyterHub in this &lt;a href="https://github.com/CryoInTheCloud/hub-image"&gt;public repository&lt;/a&gt;.&lt;/p&gt;
</content><category term="cloud computing"/><category term="education"/><category term="events"/><category term="geoscience"/><category term="JupyterHub"/><category term="science"/><category term="workshops"/></entry><entry><title>From intern to mentor</title><link href="https://blog.jupyter.org/posts/2023/from-intern-to-mentor/" rel="alternate"/><published>2023-06-19T08:02:00+00:00</published><updated>2023-06-19T08:02:00+00:00</updated><author><name>Georgiana Dolocan</name></author><id>tag:blog.jupyter.org,2023-06-19:/posts/2023/from-intern-to-mentor/</id><summary type="html">&lt;p&gt;Four years ago, Project Jupyter participated for the first time in the Outreachy program. And at the end of last year, during the December round, three more awesome interns joined the project.&lt;/p&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;Four years ago, Project Jupyter participated for &lt;a href="https://blog.jupyter.org/posts/2018/outreachy-jupyter-supporting-diversity-in-open/"&gt;the first time in the Outreachy program&lt;/a&gt;. And at the end of last year, during the December round, &lt;a href="https://blog.jupyter.org/posts/2022/introducing-jupyterhubs-outreachy-interns-december-2022/"&gt;three more awesome interns joined the project&lt;/a&gt;. Because I was lucky enough to be part of this program both times, first time as an intern and second time as a mentor, in this post I will share the parts that were the most impactful and contributed the most to my growth as both mentor and engineer. I hope this will inspire other interns, to start their journey, but also other community members into becoming mentors.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;When I first interacted with the Jupyter community, I remember I was impressed by how welcoming everyone was, how well organized they seemed, how promptly questions got answered and how fast code got reviewed. This was especially impressive during the &lt;a href="https://www.outreachy.org/docs/applicant/#make-contributions"&gt;contribution phase&lt;/a&gt; when prospect interns were everywhere at the same time, we were generating crazy amount of work for mentors and the community when asking for guidance and tackling tasks.&lt;/p&gt;
&lt;p&gt;When the internship ended I realized how much I appreciated this process compared to other internships. The contribution phase made me feel very motivated because of the opportunity to work on &lt;strong&gt;real&lt;/strong&gt; tasks, with &lt;strong&gt;impact&lt;/strong&gt; for the entire community.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;All the work traffic, immense quantity of GitHub notifications, emails, questions, etc., were totally opaque to me as an intern, they seemed to just be magically handled by mentors. I now know this seamless interaction is made of some very special ingredients like team work, time commitment and hard work, nothing magic about it.&lt;/p&gt;
&lt;h2 id="scoping-the-project-the-most-challenging-part"&gt;Scoping the project, the most challenging part&lt;/h2&gt;
&lt;p&gt;I believe scoping the project was the part that I found the most challenging as a first time mentor.&lt;/p&gt;
&lt;p&gt;The plan I had in mind for how to create the project roadmap, was to &lt;strong&gt;define a few tasks&lt;/strong&gt; that were not very tightly scoped, &lt;strong&gt;choose one&lt;/strong&gt; to start with, allocate time for the intern to &lt;strong&gt;research&lt;/strong&gt; about it, have synchronous meetings to &lt;strong&gt;collaboratively refine&lt;/strong&gt; it, then &lt;strong&gt;implement&lt;/strong&gt; it, &lt;strong&gt;review&lt;/strong&gt;, and then &lt;strong&gt;repeat&lt;/strong&gt; for next task. And although this was a good first plan, I failed to recognize when it stopped working and didn’t realize it’s important to pause and adapt the plan.&lt;/p&gt;
&lt;p&gt;It took me some time and guidance from others in the community, to realize that sometimes, &lt;strong&gt;constraints are beneficial&lt;/strong&gt; and allowing complete implementation freedom over a task, can be overwhelming. For finding the appropriate &lt;em&gt;[freedom — constraint]&lt;/em&gt; balance I needed to experimented with different task sizes, until tasks had a less overwhelming learning curve. This fosters and grows confidence and improves time management skills.&lt;/p&gt;
&lt;p&gt;I found this to be particularly tricky because this balance can be hard to achieve when creating a project roadmap. The hidden complexities of a project, existing skills, or any prior experience managing a project from scratch, are hard to know and plan around in the very first iteration.&lt;/p&gt;
&lt;p&gt;Another challenge of being a mentor that is usually hidden is the &lt;strong&gt;context switch penalty&lt;/strong&gt; between mentor time and daily job responsibilities. A mentor needs to fine tune the amount of intern interaction and involvement in the project implementation so that context switches from daily responsibilities are as soft as possible. It’s also critical that a mentor has full support and transparent communication with the daily job management so that work responsibilities don’t spill over into mentoring time, otherwise this can lead to stress and a sub-optimal experience for the intern.&lt;/p&gt;
&lt;h2 id="asking-questions-publicly-the-biggest-achievement"&gt;Asking questions publicly, the biggest achievement&lt;/h2&gt;
&lt;p&gt;The open source comes with a challenge attached to it by default, which is &lt;strong&gt;being comfortable communicating in the open and asking questions publicly&lt;/strong&gt;. The time and work that needs to go into fostering this skill needs to be taken into account from the very beginning and it’s extremely important to consider it from the project proposal and roadmap definition phase. It will help set the correct project expectations, and expose an otherwise hidden complexity of open source project maintainability.&lt;/p&gt;
&lt;p&gt;This was a challenge that was more difficult to overcome than expected, because in our case it involved, &lt;strong&gt;a first time mentor, a first time intern&lt;/strong&gt;, and a project that required diving into the codebase of lots of other different projects in the ecosystem, so &lt;strong&gt;guidance from the entire community&lt;/strong&gt; and asking questions was crucial.&lt;/p&gt;
&lt;p&gt;My intern, Sheila was very determined and courageous and she received great care and support from the entire community in overcoming this obstacle. She is now a key maintainer &lt;a href="https://github.com/jupyterhub/pytest-jupyterhub"&gt;of the internship project&lt;/a&gt; she worked on, asking and answering questions without issues. Checkout out her many achievements captured in &lt;a href="https://hackmd.io/cvqPq6XVQbaYVndwFvJ0Kw?view"&gt;this list (not complete)&lt;/a&gt; and &lt;a href="https://cfp.jupytercon.com/2023/talk/HNTKXF/"&gt;her presentation&lt;/a&gt; about the Reusable JupyterHub Pytest Plugin at JupyterCon. A recording of her talk should soon be available on &lt;a href="https://www.youtube.com/@JupyterCon"&gt;JupyterCon’s YouTube channel&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="mentor-training-mentor-shadowing-co-mentoring-the-best-allies"&gt;Mentor training, mentor shadowing, co-mentoring, the best allies&lt;/h2&gt;
&lt;p&gt;I am extremely grateful to have had the support of the other mentors and the community during theses three mentoring months.&lt;/p&gt;
&lt;p&gt;In particular, I am very grateful for Sarah Gibson, &lt;a href="https://blog.jupyter.org/posts/2021/czi-awards-three-eoss-grants-to-jupyter-community/"&gt;the Jupyter strategic lead&lt;/a&gt; and our Community Coordinator with Outreachy, for organizing for us to get &lt;strong&gt;mentor training&lt;/strong&gt; beforehand through the &lt;a href="https://openlifesci.org/"&gt;OLS community&lt;/a&gt;. I found that to be very helping and ground setting and it made me feel more empowered.&lt;/p&gt;
&lt;p&gt;I also appreciated and found really useful the &lt;strong&gt;mentor shadowing sessions&lt;/strong&gt; that I did with Sarah and the &lt;strong&gt;demo session&lt;/strong&gt; that Min RK hold with all the interns and mentors. They were both great opportunities for me to observe and learn from the other mentors and get feedback from them.&lt;/p&gt;
&lt;p&gt;Co-mentoring was something that was considered during this round, but because we wanted to select all these great interns we ended up not mentoring in teams. But this appears as a great approach of introducing first-time mentors.&lt;/p&gt;
&lt;h2 id="it-was-all-worth-it-the-takeway"&gt;It was all worth it, the takeway&lt;/h2&gt;
&lt;p&gt;The JupyterHub project got to improve its documentation, accessibility and testing thanks to this program and to the three amazing interns that worked with us during this round ❤️. In addition, this internship round helped us create &lt;a href="https://jupyterhub-outreachy.readthedocs.io/en/latest/"&gt;a place where people can learn about JupyterHub’s experience with Outreachy&lt;/a&gt; and &lt;a href="https://github.com/jupyterhub/jupyterhub-python-repo-template"&gt;a template repository&lt;/a&gt; to be used for quickly generating other JupyterHub Python sub-repositories that follow the standards of the organization.&lt;/p&gt;
&lt;p&gt;On the personal side now that the internship is over, I can happily say that it was very enlightening and humbling to be on the mentoring side as well. Even if it’s challenging, you get an amazing feeling when you give back and channel all the effort and kindness that shaped you and that you received as a mentee from other people.&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
</content><category term="community"/><category term="JupyterHub"/><category term="Outreachy"/></entry><entry><title>Accurately counting Daily, Weekly &amp; Monthly active users on JupyterHub</title><link href="https://blog.jupyter.org/posts/2023/accurately-counting-daily-weekly-monthly-active-users/" rel="alternate"/><published>2023-03-27T09:16:00+00:00</published><updated>2023-03-27T09:16:00+00:00</updated><author><name>Yuvi Panda</name></author><id>tag:blog.jupyter.org,2023-03-27:/posts/2023/accurately-counting-daily-weekly-monthly-active-users/</id><summary type="html">&lt;p&gt;Being able to say ‘we served X unique users over the last month’ (the Monthly Active User metric) is very helpful when advocating for resources for a JupyterHub your organization is running.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Being able to say ‘we served X unique users over the last month’ (the &lt;a href="https://en.wikipedia.org/wiki/Active_users"&gt;Monthly Active User metric&lt;/a&gt;) is very helpful when advocating for resources for a JupyterHub your organization is running. However, until now, figuring out that number &lt;em&gt;accurately&lt;/em&gt; has been difficult, requiring keeping and analysing JupyterHub logs.&lt;/p&gt;
&lt;p&gt;That changes with JupyterHub 3.1! &lt;a href="https://github.com/jupyterhub/jupyterhub/pull/4214"&gt;This Pull Request&lt;/a&gt; adds daily, weekly, and monthly active user metrics to JupyterHub, accessible via the prometheus interface by hitting the &lt;code&gt;/metrics&lt;/code&gt; URL on your JupyterHub. These metrics are calculated by JupyterHub itself, and are pretty accurate as it already keeps track of when a user was last active. This relies metric on each JupyterHub user matching an actual user, so if you are using your JupyterHub deployment purely as an API with ephemeral users (as &lt;a href="https://github.com/jupyterhub/binderhub/"&gt;binderhub&lt;/a&gt; does, for example) or delete inactive users, these will not be useful numbers.&lt;/p&gt;
&lt;p&gt;Ideally, you should have a &lt;a href="https://prometheus.io/"&gt;prometheus&lt;/a&gt; instance to scrape and store metrics from your JupyterHub over time, so you can track this metric over time. However, in a pinch, you can also go directly to &lt;code&gt;https://&amp;lt;your-hub-url&amp;gt;/hub/api/metrics&lt;/code&gt; and see the current value of these metrics. They are in the &lt;a href="https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md"&gt;prometheus exposition format&lt;/a&gt;, but you can look for something like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# HELP jupyterhub_active_users number of users who were active in the given time period&lt;/span&gt;
&lt;span class="c1"&gt;# TYPE jupyterhub_active_users gauge&lt;/span&gt;
jupyterhub_active_users&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;period&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;24h&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;610&lt;/span&gt;.0
jupyterhub_active_users&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;period&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;7d&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2800&lt;/span&gt;.0
jupyterhub_active_users&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;period&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;30d&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4526&lt;/span&gt;.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This denotes that this particular hub had 610 daily active users (active over the last 24 hours), 2800 weekly users (over last 7d) and 4526 monthly ones (over the last 30 days). Very helpful if you want to quickly add numbers to a report :)&lt;/p&gt;
&lt;p&gt;Note that depending on your hub’s configuration, access to the &lt;code&gt;/metrics&lt;/code&gt; endpoint might &lt;a href="https://jupyterhub.readthedocs.io/en/stable/api/app.html#jupyterhub.app.JupyterHub.authenticate_prometheus"&gt;require authentication&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you &lt;em&gt;do&lt;/em&gt; have a prometheus installation for your JupyterHub, you may benefit from deploying &lt;a href="https://github.com/jupyterhub/grafana-dashboards"&gt;the JupyterHub Grafana Dashboards&lt;/a&gt;. These are targeted at installations of &lt;a href="https://z2jh.jupyter.org"&gt;zero-to-jupyterhub on kubernetes&lt;/a&gt;, and provide a lot of useful usage &amp;amp; diagnostic information.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Grafana Dashboard showing “Hub Usage Stats” for a JupyterHub deployment. Four panels, clockwise: Current Active Users, Daily Active Users, Weekly Active Users, Monthly Active Users." src="https://blog.jupyter.org/posts/2023/accurately-counting-daily-weekly-monthly-active-users/images/001-0_VYHSKwQ5Jp-L3ArS.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Grafana Dashboard showing “Hub Usage Stats” for a JupyterHub deployment. Four panels, clockwise: Current Active Users, Daily Active Users, Weekly Active Users, Monthly Active Users.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Happy report writing!&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
</content><category term="DevOps"/><category term="JupyterHub"/></entry><entry><title>Online Collaboration Café launch: JupyterHub team meetings to become more collaborative spaces!</title><link href="https://blog.jupyter.org/posts/2023/online-collaboration-cafe-launch-jupyterhub-team/" rel="alternate"/><published>2023-02-27T08:49:00+00:00</published><updated>2023-02-27T08:49:00+00:00</updated><author><name>Sarah Gibson</name></author><id>tag:blog.jupyter.org,2023-02-27:/posts/2023/online-collaboration-cafe-launch-jupyterhub-team/</id><summary type="html">&lt;p&gt;The JupyterHub team are refactoring our monthly meeting into a collaborative, co-working space that is more accessible and inclusive to those who are just getting started in the community — an Online Collaboration Café!&lt;/p&gt;</summary><content type="html">&lt;figure&gt;
&lt;img alt="A cartoon of a person and their black and white dog, sat at a desk using a laptop. Squares containing profiles of different people wearing headphones are emanating from the laptop, indicating that the person at the desk is participating in a remote, collaborative activity." src="https://blog.jupyter.org/posts/2023/online-collaboration-cafe-launch-jupyterhub-team/images/001-1_9GSBPtjxJNpvUXCFcaL9ng.jpeg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;This illustration is created by Scriberia with The Turing Way community. Used under a CC-BY 4.0 licence. DOI: &lt;a href="https://doi.org/10.5281/zenodo.3332807"&gt;10.5281/zenodo.3332807&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The JupyterHub team are refactoring our monthly meeting into a collaborative, co-working space that is more accessible and inclusive to those who are just getting started in the community — an Online Collaboration Café! This blog post aims to explain what that means, and what to expect when you attend. We plan to hold our first Online Collaboration Café on &lt;strong&gt;21st March 2023&lt;/strong&gt;. Please come along and let us know your feedback!&lt;/p&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;The team meeting will be held in a new format for 2 hours in the original time slot. Instead of a typical meeting style with an agenda, the group will be divided into breakout rooms to work more collaboratively on ideas and perhaps begin actioning them. There will always be breakout rooms available for onboarding newcomers and those who wish some dedicated time to undertake maintenance tasks, as well as a quiet working space in the main room. Participants should feel free to swap rooms and join/drop out as they need.&lt;/p&gt;
&lt;h2 id="why-the-change"&gt;Why the change?&lt;/h2&gt;
&lt;p&gt;The JupyterHub community often cite the team meetings as a touchpoint for newcomers to familiarise themselves with the JupyterHub project. However, this is not always the case. The team meetings have an emergent agenda built by the community members — which is great! — but it also means that it is a potluck as to whether the meeting you happen to attend will actually be useful depending on the agenda, and a newcomer may have to attend multiple meetings over a long period before feeling comfortable to ask questions and know where they can begin to help.&lt;/p&gt;
&lt;p&gt;By reformatting the meeting into a collaborative co-working space using breakout rooms, we can cater for both the need of newcomers to be oriented to the project, and for the community to discuss in-depth topics in an emergent nature.&lt;/p&gt;
&lt;h2 id="what-is-an-online-collaboration-cafe"&gt;What is an Online Collaboration Café?&lt;/h2&gt;
&lt;p&gt;The Collaboration Café is a concept that was developed by &lt;a href="https://the-turing-way.netlify.app"&gt;&lt;em&gt;The Turing Way&lt;/em&gt; community&lt;/a&gt;, and you can read more about it and how they are run in their &lt;a href="https://the-turing-way.netlify.app/community-handbook/coworking/coworking-collabcafe.html#chairing-an-online-collaboration-cafe"&gt;Community Handbook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In short, an Online Collaboration Café utilises breakout rooms and &lt;a href="https://en.wikipedia.org/wiki/Pomodoro_Technique"&gt;pomodoro sprints&lt;/a&gt; to allow groups of community members to work together on a topic that best suits them. The space between the pomodoros are used as shareouts to the rest of the group, or as biobreaks.&lt;/p&gt;
&lt;h2 id="what-are-the-logistics"&gt;What are the logistics?&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;This is an online café. We will meet on a video call.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We will be using the same alternating time slot that the team meetings used to occur in, but the slot will now be two hours. You can view the &lt;a href="https://jupyterhub-team-compass.readthedocs.io/en/latest/meetings/index.html#meeting-calendars"&gt;Team Calendar&lt;/a&gt; for details.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A chair will always be present in the main room to manage breakout rooms and greet folk who may arrive mid-sprint.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There will always be some default breakout rooms available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Onboarding:&lt;/strong&gt; For new arrivals to the community. A member of the team will be available on the call to support anyone wanting to learn more about collaborating on GitHub, getting a virtual tour of our GitHub organisation, and help you in any way we can.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maintenance:&lt;/strong&gt; Folks working in this room will be triaging issues, reviewing pull requests, and other maintenance-related activities across the JupyterHub organisation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quiet working in the main room:&lt;/strong&gt; If you would just like some quiet time dedicated to any JupyterHub-related work you have, you are invited to hang out in the main room (and keep the chair company 😉)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="what-will-happen-when-i-attend"&gt;What will happen when I attend?&lt;/h2&gt;
&lt;p&gt;When you arrive to the Online Collaboration Café, there will first be some housekeeping, such as introductions, Code of Conduct review. There will then be some goal setting around what folks are hoping to achieve during the time. These goals will determine the topics for the breakout rooms. Any attendee is welcome to: suggest their own topic, join a suggested topic, join one of the default rooms, or work quietly in the main room. The breakouts will then run in sprints with breaks to share their progress. The Café is closed with some reflections, for example: how did your work progress, what should the project think about working towards next?&lt;/p&gt;
&lt;p&gt;Here is an example schedule of how an Online Collaboration Café could happen inspired by &lt;a href="https://the-turing-way.netlify.app/community-handbook/coworking/coworking-collabcafe.html#schedule"&gt;&lt;em&gt;The Turing Way&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Activity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Start&lt;/td&gt;
&lt;td&gt;Welcome, CoC review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10 mins&lt;/td&gt;
&lt;td&gt;Introductions and goal setting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20 mins&lt;/td&gt;
&lt;td&gt;Pomodoro 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5 mins&lt;/td&gt;
&lt;td&gt;Break&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20 mins&lt;/td&gt;
&lt;td&gt;Pomodoro 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5 mins&lt;/td&gt;
&lt;td&gt;Break&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20 mins&lt;/td&gt;
&lt;td&gt;Open discussion: celebrations, reflections, future plans&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5 mins&lt;/td&gt;
&lt;td&gt;Close&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="2-hours-seems-like-a-long-time-why-not-multiple-meetings"&gt;2 hours seems like a long time… Why not multiple meetings?&lt;/h2&gt;
&lt;p&gt;Various individual meetings covering separate topics, such as onboarding and maintenance, were considered. However given that the majority of JupyterHub’s community are volunteers, it didn’t seem practical to fill up the calendar with lots of meetings. Another reason to use parallel breakout rooms is that participants can swap rooms if the current conversation doesn’t appeal to them, as if you were at tables in a real café. &lt;em&gt;This practice is highly encouraged.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The extension to 2 hours is important because this is a pivot towards collaboration and co-working, and we want to provide a dedicated time for folk to achieve that and begin actioning ideas. However it is a large chunk of time to devote when we are all busy, and so it is not a requirement to arrive on time and participate for the full 2 hours. &lt;em&gt;Joining when you can and dropping when you need to is encouraged and doesn’t require apologies.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="will-there-be-cake-at-this-cafe"&gt;Will there be cake at this café?&lt;/h2&gt;
&lt;p&gt;It is an online café so there will be as many virtual cakes as you like! 🍰🍰🍰&lt;/p&gt;
&lt;p&gt;This is an informal space, so you are encouraged to bring along any beverages and/or snacks. We hope you will join us!&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
</content><category term="community"/><category term="JupyterHub"/></entry><entry><title>Introducing JupyterHub’s Outreachy interns! — December 2022 Cohort</title><link href="https://blog.jupyter.org/posts/2022/introducing-jupyterhubs-outreachy-interns-december-2022/" rel="alternate"/><published>2022-12-07T07:45:00+00:00</published><updated>2022-12-07T07:45:00+00:00</updated><author><name>Sarah Gibson</name></author><id>tag:blog.jupyter.org,2022-12-07:/posts/2022/introducing-jupyterhubs-outreachy-interns-december-2022/</id><summary type="html">&lt;p&gt;As part of the community strategic support project funded by CZI’s EOSS grant series, the JupyterHub sub-project has funding to support Outreachy interns through four cohorts over the next two years. We would like to introduce you to the first cohort and the projects they will be working on!&lt;/p&gt;</summary><content type="html">&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2022/introducing-jupyterhubs-outreachy-interns-december-2022/images/001-1_mRtgDdoRwjO3Kb2nSGOsdw.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;As part of the &lt;a href="https://blog.jupyter.org/posts/2021/czi-awards-three-eoss-grants-to-jupyter-community/"&gt;community strategic support project funded by CZI’s EOSS grant series&lt;/a&gt;, the JupyterHub sub-project has funding to support Outreachy interns through four cohorts over the next two years. We would like to introduce you to the first cohort and the projects they will be working on!&lt;/p&gt;
&lt;h2 id="ogoh-blessing-onyowoicho-improve-accessibility-in-jupyterhub"&gt;Ogoh Blessing Onyowoicho — Improve Accessibility in JupyterHub&lt;/h2&gt;
&lt;p&gt;Accessibility is the ability of tools (in our case web tools) to be used by a variety of communities with different disabilities. There are a variety of standards and tools for evaluating and ensuring that a web page can be used effectively by as many people as possible. Work by the &lt;a href="https://jupyter-accessibility.readthedocs.io"&gt;Accessibility team&lt;/a&gt; is ongoing to define a set of standard tools to improve accessibility across the Jupyter ecosystem.&lt;/p&gt;
&lt;p&gt;The JupyterHub project is working to improve the accessibility of its pages to ensure we are providing tools that are as useful as they can be to as many people as we can. During the internship, we will evaluate JupyterHub’s accessibility, find ways to improve it, and integrate accessibility testing into the development process, in collaboration with the Accessibility team, to ensure we do a better job going forward.&lt;/p&gt;
&lt;h3 id="ogoh-blessing-says"&gt;Ogoh Blessing says:&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;My name is Ogoh Blessing Onyowoicho. I am a self-taught Frontend developer based in Lagos, Nigeria and I am an Outreachy intern working on Improving the accessibility of JupyterHub.&lt;br&gt;
I am excited to work on JupyterHub because it is giving me the opportunity to use skills that I have accrued over the years to proffer solutions to problems that affect people’s lives directly. On hearing accessibility, the first thought one has is that it involves building web products that people with special needs can use seamlessly. Though this is part of it, accessibility goes way beyond this. It involves building products that different users (e.g users at different locations, users with different devices etc) can use easily. The thought of contributing to improving the experience of so many people alone excites me.&lt;br&gt;
In the coming months, I hope to learn and continue to hone my skills as I am guided by my mentors and members of the community I get to interact with.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="allan-wasega-restructure-and-improve-jupyterhub-documentation-by-implementing-the-diataxis-framework"&gt;Allan Wasega — Restructure and improve JupyterHub documentation by implementing the Diátaxis framework&lt;/h2&gt;
&lt;p&gt;JupyterHub has a range of documentation that covers both developer and user audiences in order to help them deploy, maintain, and use their own instance of a JupyterHub. The success of an open source software project to (i) be adopted by users, and (ii) receive meaningful contributions relies heavily on the quality, navigability and accessibility of documentation so that users and developers have all the information they need to achieve what they want to do.&lt;/p&gt;
&lt;p&gt;A framework for organising technical documentation has arisen called &lt;a href="https://diataxis.fr"&gt;diátaxis&lt;/a&gt;. It takes a systematic approach to understanding user requirements of documentation throughout the lifecycle of interaction with a product and posits that different user needs require different approaches in creation of the documentation, as well as a layout to navigate these different “modes” of documentation.&lt;/p&gt;
&lt;p&gt;This project will focus on a refactoring of the documentation for the &lt;a href="https://github.com/jupyterhub/jupyterhub"&gt;JupyterHub package&lt;/a&gt;. We will begin by performing a review of the present documentation, categorise these into the diataxis framework, and then restructure the documentation files in the repository. Once we have transformed the documentation into this framework, it will be much easier to identify missing and unclear documentation (those that were difficult to categorise). We can then begin to curate resources that can fill the gaps and improve documentation that is not specific enough.&lt;/p&gt;
&lt;h3 id="allan-says"&gt;Allan says:&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;I am Allan Wasega, from Nairobi, Kenya. Broadly, I like to describe myself as a researcher and a writer. Researcher because looking into things to find patterns or hidden information has always been of interest to me. Writer because I figured early on that words allow me to express myself and to communicate to a larger audience than that inside my head :). As a Computer Science student, I looked for ways to bring these two skills together within the realm of computing and that is how I found myself in the technical writing space.&lt;br&gt;
As an undergraduate student, I used Jupyter Notebooks extensively for most of my programming assignments and projects. As a result, when making my Outreachy application, the JupyterHub project immediately piqued my interest because I did not know that there was a way to serve Jupyter Notebooks to multiple users, such as within a classroom setting. Presently, I serve as a mentor at KamiLimu, which is a mentorship program for students pursuing technology-aligned courses in tertiary institutions in Kenya. One of the objectives of KamiLimu is to introduce students to tech specializations such as Data Science and Machine Learning, which, from experience, uses Jupyter Notebooks! Therefore, I am excited to work on JupyterHub because I will be learning about and helping to improve a product I hold dear and which I can use to advance the skills of the next generation of computer technologists in Kenya.&lt;br&gt;
First, I hope to gain a deep understanding of how JupyterHub works so as to spread the word about it and its functionalities. Second, I hope to apply and advance my technical writing skills. I encountered the Diataxis Framework earlier this year while working as a technical writer at Tingle Software, a Nairobi-based software company. I have also been following Daniele Procida (the author of the framework) on Twitter for a while now and his work has been quite inspiring. Through this project, I will apply the Diataxis Framework to restructure JupyterHub’s documentation and, in doing so, further my understanding of the framework. Finally, I am passionate about mentorship, especially in the tech field. Therefore, besides expanding my professional and personal networks, this project will enable me to learn how to conduct mentorship within a global setting, and I can, in turn, apply this knowledge within my local community.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="sheila-kahwai-create-a-reusable-jupyterhub-pytest-plugin"&gt;Sheila Kahwai — Create a reusable JupyterHub pytest plugin&lt;/h2&gt;
&lt;p&gt;JupyterHub is a modular and extensible project, with parts, like the proxy, authenticator and spawner, that can be easily changed and extended. Testing the functionality of these components against JupyterHub is important and it requires various hub setups that can sometimes become complicated.&lt;/p&gt;
&lt;p&gt;Currently, each of these hub components and the hub itself define their own testing infrastructure, building everything from the ground up using the pytest framework. But some of this complex work is either repetitive across JupyterHub sub-projects, or under-specified for some of them.&lt;/p&gt;
&lt;p&gt;This project will abstract out these common parts into a separate testing framework. This framework should be a pip-installable pytest plugin that would provide various hub functionalities through pytest fixtures. These fixtures can then be re-used by JupyterHub and its components to bootstrap their own testing suite.&lt;/p&gt;
&lt;p&gt;Integrating this plugin will drive some important refactoring work of the current testing architecture of JupyterHub and have a great impact in improving the overall test coverage, maintainability and continuity of the JupyterHub project.&lt;/p&gt;
&lt;h3 id="sheila-says"&gt;Sheila says:&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;My name is Sheila Kahwai. I am a self-taught python developer from Nairobi, Kenya, working to specialize in back-end engineering.&lt;br&gt;
I am excited to work on JupyterHub because it has made many products I have used throughout my learning journey. It is a privilege to work with a diverse community that has created products that are very useful to equally diverse users like myself.&lt;br&gt;
While creating a reusable JupyterHub pytest plugin, I hope to gain more insight into creating plugins for massive codebases to improve maintainability and scalability with clean and reusable code. Through this project, I look forward to improving the overall testing infrastructure of the various JupyterHub components.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Welcome to the interns! We’re so excited to start working with you!&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
</content><category term="accessibility"/><category term="documentation"/><category term="JupyterHub"/><category term="Outreachy"/></entry><entry><title>Securely pushing to GitHub from a JupyterHub with gh-scoped-creds</title><link href="https://blog.jupyter.org/posts/2022/securely-pushing-to-github-from-a-jupyterhub/" rel="alternate"/><published>2022-04-21T16:54:00+00:00</published><updated>2022-04-21T16:57:00+00:00</updated><author><name>Yuvi Panda</name></author><id>tag:blog.jupyter.org,2022-04-21:/posts/2022/securely-pushing-to-github-from-a-jupyterhub/</id><summary type="html">&lt;p&gt;Many JupyterHub users want to push and pull their content from GitHub in order to collaborate and share their work.&lt;/p&gt;</summary><content type="html">&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2022/securely-pushing-to-github-from-a-jupyterhub/images/001-1_9E0cif7g07xWAOfsFFmijw.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;Many JupyterHub users want to push and pull their content from GitHub in order to collaborate and share their work. However, working on a JupyterHub means working on &lt;em&gt;shared infrastructure&lt;/em&gt;, not your own laptop, and this poses some extra security risks that have made two-way sync with GitHub more difficult. This post describes &lt;code&gt;gh-scoped-creds&lt;/code&gt;, a new tool to make it quick and easy to authorize a JupyterHub session with push access to GitHub in a secure and simple manner.&lt;/p&gt;
&lt;p&gt;GitHub user credentials are &lt;a href="https://github.blog/2022-04-15-security-alert-stolen-oauth-user-tokens/"&gt;high value targets&lt;/a&gt; for cybercriminals in today’s security environment, and any system that stores these credentials long term paints an unwanted target on itself. Current solutions — putting an ssh key on the JupyterHub, using a &lt;a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token"&gt;personal access token&lt;/a&gt; or deploy keys — involve storing long term valid GitHub credentials in the filesystem. As users can do this by themselves without admin intervention, admins often are not aware these (often unencrypted) credentials are on their filesystems. If an attacker compromises an ssh key or a personal access token, they have unlimited access to all GitHub repos the compromised user had access to, including repos in high-impact GitHub organizations. In the recent credential theft incident, Travis-CI and Heroku were ‘lucky’ in that the &lt;a href="https://github.blog/2022-04-15-security-alert-stolen-oauth-user-tokens/"&gt;attackers accessed npm infrastructure&lt;/a&gt; — and since npm is owned by GitHub, GitHub was able to detect that Travis CI and Heroku had compromised credentials. You and the users of repositories you have rights to might not be so lucky. It’s 2022, and &lt;a href="https://github.com/cncf/tag-security/blob/main/supply-chain-security/compromises/README.md"&gt;supply chain attacks are everywhere&lt;/a&gt; — you aren’t special, you’re just one link in a long chain attackers use to get to someone else.&lt;/p&gt;
&lt;p&gt;There is a clear need for a simple solution that lets users push to GitHub from JupyterHub in a secure manner without admins having to worry about securing high-value GitHub credentials long term. It is not acceptable to “Just Say No” to users wanting this functionality either — if you try to ‘sacrifice’ usability for security, you end up getting neither.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/yuvipanda/gh-scoped-creds/"&gt;&lt;code&gt;gh-scoped-creds&lt;/code&gt;&lt;/a&gt; attempts to solve this problem by allowing users to grant &lt;em&gt;time-limited&lt;/em&gt; push access to &lt;em&gt;specific repositories&lt;/em&gt; to &lt;em&gt;specific JupyterHub installations&lt;/em&gt; in a user friendly way.&lt;/p&gt;
&lt;p&gt;Here’s a quick GIF running through the user workflow.&lt;/p&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2022/securely-pushing-to-github-from-a-jupyterhub/images/002-1_B3qjACXLBG9pBOlzY8WNxA.mp4" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;Push access is scoped both by time (credentials expire after 8 hours) as well as repository (access is granted per-repository, per-hub). While you need to refresh credentials every 8 hours, the list of repositories is remembered until you explicitly revoke access. You can always grant access to your own personal repositories, but repositories belonging to organisations might require admins to approve push access to them.&lt;/p&gt;
&lt;p&gt;You can also run the command from the terminal as &lt;code&gt;gh-scoped-creds&lt;/code&gt; instead of using the IPython magic &lt;code&gt;%ghscopedcreds&lt;/code&gt; as shown in the demo. This way, you can also use this from a HPC system, not just a JupyterHub!&lt;/p&gt;
&lt;p&gt;Setting this up for your JupyterHub requires a tiny bit of work from the admin — see &lt;a href="https://github.com/yuvipanda/gh-scoped-creds/"&gt;the project README&lt;/a&gt; for more details. Shouldn’t take long, and it’s a one-time task. Once that’s set up, your users can securely push to GitHub from the comfort of their JupyterHubs!&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href="https://twitter.com/fperez_org"&gt;Fernando Perez&lt;/a&gt; for using his &lt;a href="https://classes.berkeley.edu/content/2021-spring-stat-159-001-lec-001"&gt;stat159 class&lt;/a&gt; at &lt;a href="https://www.berkeley.edu/"&gt;UC Berkeley&lt;/a&gt; to test this project out.&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
</content><category term="GitHub"/><category term="JupyterHub"/><category term="security"/></entry><entry><title>JupyterHub 2.0</title><link href="https://blog.jupyter.org/posts/2021/jupyterhub-2-0/" rel="alternate"/><published>2021-12-01T14:15:00+00:00</published><updated>2021-12-01T14:15:00+00:00</updated><author><name>Min RK</name></author><id>tag:blog.jupyter.org,2021-12-01:/posts/2021/jupyterhub-2-0/</id><summary type="html">&lt;p&gt;Hubs and roles and scopes, oh my!&lt;/p&gt;
</summary><content type="html">&lt;p&gt;We’ve just published JupyterHub 2.0, our biggest release in a while.&lt;/p&gt;
&lt;h2 id="roles-and-scopes-rbac"&gt;Roles and scopes (RBAC)&lt;/h2&gt;
&lt;p&gt;Thanks to the work of Omar Richardson and Ivana Huskova and more contributors along the way, JupyterHub now has fine-grained control of permissions, via &lt;strong&gt;scopes&lt;/strong&gt; (a &lt;strong&gt;role&lt;/strong&gt; is a named collection of scopes).&lt;/p&gt;
&lt;p&gt;This makes JupyterHub more secure because you no longer need to give every user or service full admin permissions if they need to take one elevated action (such as a cull-idle service). Now, you can give users and services exactly the permissions they actually need. &lt;code&gt;admin&lt;/code&gt; still exists, but nothing should need to be an admin anymore. Fine-grained scopes also allow new configurations that weren’t previously available, such as granting instructors permission to access their students’ servers, which is useful with JupyterLab’s new real-time collaboration features, without needing to grant them full admin permissions, or even access to servers of users not in their specific class.&lt;/p&gt;
&lt;p&gt;The significant change in how permissions work means that upgrading to 2.0 requires some downtime. You will need to shut down all services and single-user servers across the upgrade, and make sure you upgrade JupyterHub to 2.0 in both the user environment and the Hub environment at the same time.&lt;/p&gt;
&lt;p&gt;All tokens issued prior to the 2.0 upgrade will be revoked.&lt;/p&gt;
&lt;p&gt;As always, &lt;strong&gt;&lt;a href="https://jupyterhub.readthedocs.io/en/2.0.0/admin/upgrading.html"&gt;back up your database&lt;/a&gt; before upgrading&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Read more about roles and scopes &lt;a href="https://jupyterhub.readthedocs.io/en/2.0.0/rbac/"&gt;in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="jupyterlab-by-default"&gt;JupyterLab by default&lt;/h2&gt;
&lt;p&gt;2.0 also marks JupyterHub’s transition to using JupyterLab as the default UI. You can stick with the classic notebook server with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;c.Spawner.environment = {
    &amp;quot;JUPYTERHUB_SINGLEUSER_APP&amp;quot;: &amp;quot;notebook.notebookapp.NotebookApp&amp;quot;,
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;or try &lt;strong&gt;RetroLab&lt;/strong&gt;, a classic-style UI built on the newer Jupyter Server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;c.Spawner.default_url = &amp;quot;/retro/&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(assuming you’ve installed it in the user environment, with e.g. &lt;code&gt;pip install retrolab&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id="and-more"&gt;And more&lt;/h2&gt;
&lt;p&gt;There are various other changes and improvements in 2.0, including a new admin UI, API pagination, and no longer relying on any command-line arguments for single-user servers. Check out the &lt;a href="https://jupyterhub.readthedocs.io/en/2.0.0/changelog.html"&gt;changelog&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;We encourage you to take 2.0 for a spin, try out the roles and scopes, and &lt;a href="https://discourse.jupyter.org/c/jupyterhub/10"&gt;let us know&lt;/a&gt; how it goes.&lt;/p&gt;
&lt;p&gt;Thanks to all the contributors who helped us with 2.0, especially prerelease testers!&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
</content><category term="JupyterHub"/><category term="releases"/></entry><entry><title>Setting up a “Production Ready” TLJH deployment</title><link href="https://blog.jupyter.org/posts/2021/setting-up-a-production-ready-tljh-deployment/" rel="alternate"/><published>2021-06-04T17:05:00+00:00</published><updated>2021-06-04T17:05:00+00:00</updated><author><name>Yuvi Panda</name></author><id>tag:blog.jupyter.org,2021-06-04:/posts/2021/setting-up-a-production-ready-tljh-deployment/</id><summary type="html">&lt;p&gt;The Littlest JupyterHub is an extremely capable hub distribution that I’d recommend for situations where you expect, on average, under 100 active users.&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://tljh.jupyter.org/"&gt;The Littlest JupyterHub&lt;/a&gt; is an extremely capable hub distribution that I’d recommend for situations where you expect, on average, under 100 active users.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="The Littlest JupyterHub is a distribution of JupyterHub for single VM instances, best-used with 1–100 users." src="https://blog.jupyter.org/posts/2021/setting-up-a-production-ready-tljh-deployment/images/001-1_4zZBoheuyfPsemCzc_O7jg.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The Littlest JupyterHub is a distribution of JupyterHub for single VM instances, best-used with 1–100 users.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="why-not-kubernetes"&gt;Why not Kubernetes?&lt;/h2&gt;
&lt;p&gt;The primary reason to use &lt;a href="https://z2jh.jupyter.org"&gt;Zero to JupyterHub on k8s&lt;/a&gt; over TLJH in cases with a smaller number of users is to reduce costs — Kubernetes can spin down nodes when not in use. However, you’ll always have at least one node running (for the hub / proxy pods) and the extra complexity that comes with it — particularly around needing to build your own docker images — may not be worth it. TLJH works perfectly well for these cases!&lt;/p&gt;
&lt;h2 id="what-is-production"&gt;What is ‘production’?&lt;/h2&gt;
&lt;p&gt;A JupyterHub that you can run securely without lots of intervention from the person who created it is what I’ll call a &lt;em&gt;production-ready&lt;/em&gt; JupyterHub. It’s a pretty arbitrary standard. In this blog post, I’ll lay out what &lt;strong&gt;I&lt;/strong&gt; want in the TLJH hubs I run before I let users on them.&lt;/p&gt;
&lt;h2 id="authentication"&gt;Authentication&lt;/h2&gt;
&lt;p&gt;Use a &lt;em&gt;real&lt;/em&gt; &lt;a href="https://tljh.jupyter.org/en/latest/howto/index.html#authentication"&gt;Authenticator&lt;/a&gt;, not the default &lt;a href="https://github.com/jupyterhub/firstuseauthenticator"&gt;&lt;code&gt;FirstUseAuthenticator&lt;/code&gt;&lt;/a&gt;. The default authenticator is pretty insecure, and should really not be used in production. If you don’t know what to use, I’ll suggest the &lt;a href="https://tljh.jupyter.org/en/latest/howto/auth/google.html"&gt;Google&lt;/a&gt; or &lt;a href="https://tljh.jupyter.org/en/latest/howto/auth/github.html"&gt;GitHub&lt;/a&gt; authenticators.&lt;/p&gt;
&lt;h2 id="enable-https"&gt;Enable HTTPS&lt;/h2&gt;
&lt;p&gt;Enable &lt;a href="https://tljh.jupyter.org/en/latest/howto/admin/https.html"&gt;HTTPS&lt;/a&gt;. An absolute security requirement now, and TLJH makes it quite easy. You &lt;em&gt;do&lt;/em&gt; need to get a domain for this to work, which can be a source of friction. Totally worth it, though.&lt;/p&gt;
&lt;h2 id="resource-limits"&gt;Resource Limits&lt;/h2&gt;
&lt;p&gt;In many systems, a single user can often write code that accidentally crashes the whole system. By default, TLJH doesn’t have any memory limits enforced per-user, but it is very easy to configure it to enforce &lt;a href="https://tljh.jupyter.org/en/latest/topic/tljh-config.html#user-server-limits"&gt;memory limits&lt;/a&gt;. Tuning these to match your needs will help prevent a single student from accidentally taking down your whole hub. I’d highly recommend &lt;a href="https://tljh.jupyter.org/en/latest/howto/admin/nbresuse.html"&gt;checking&lt;/a&gt; how much memory your typical notebook uses, and making sure you have user limits set to above that.&lt;/p&gt;
&lt;h2 id="sizing-your-vm-correctly"&gt;Sizing your VM correctly&lt;/h2&gt;
&lt;p&gt;If you choose a VM that’s too big, you’ll end up spending a lot of cash for unused resources. If it’s too small, your users will not have the resources they need to do their work. TLJH provides &lt;a href="https://tljh.jupyter.org/en/latest/howto/admin/resource-estimation.html"&gt;some helpful docs&lt;/a&gt; estimating your VM size, and you can always &lt;a href="https://tljh.jupyter.org/en/latest/howto/admin/resize.html"&gt;resize&lt;/a&gt; your VM afterwards if you get it wrong.&lt;/p&gt;
&lt;h2 id="disk-backups"&gt;Disk backups&lt;/h2&gt;
&lt;p&gt;TLJH contains everything on the VM’s disk — your user environment, users’ home directories, current hub configuration, etc. It is very important you back this up, to recover in case of disasters. Automated disk snapshots from your cloud provider are an easy way to do this. Most major cloud providers offer a way to do this — &lt;a href="https://cloud.google.com/compute/docs/disks/create-snapshots"&gt;Google Cloud&lt;/a&gt;, &lt;a href="https://www.digitalocean.com/docs/images/snapshots/"&gt;Digital Ocean&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSSnapshots.html"&gt;AWS&lt;/a&gt;, etc. Some let you automate it as well — Google &amp;amp; AWS certainly do, I’m not sure about other cloud providers. This isn’t the &lt;em&gt;best&lt;/em&gt; way to do backup — there’s approximately 1 billion ways to do so. However, this is an absolute minimum, and it might just be enough.&lt;/p&gt;
&lt;p&gt;If you want to be more fancy, I’d suggest using a separate disk / volume for your user home directories, possibly on &lt;a href="https://wiki.ubuntu.com/ZFS"&gt;ZFS&lt;/a&gt;, and snapshot much more aggressively. Talk to your nearest google search bar for your options.&lt;/p&gt;
&lt;h2 id="pin-your-public-ip"&gt;Pin your public IP&lt;/h2&gt;
&lt;p&gt;Some cloud providers change your VM’s public IP address if you start / stop them. This can be pretty bad — you’ll have to change your domain’s DNS entry, and re-acquire HTTPS. A hassle! You can tell your cloud provider to hang on to your IP even if your VM goes down / changes. And you should! DigitalOcean doesn’t require this, but &lt;a href="https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address"&gt;Google Cloud does&lt;/a&gt;. I think AWS does too, but I’m not sure how you can reserve the public IP for it — since it’s usually a domain name itself.&lt;/p&gt;
&lt;h2 id="base-environment-setup-snapshot"&gt;Base environment setup + snapshot&lt;/h2&gt;
&lt;p&gt;TLJH has a shared &lt;a href="https://conda.io"&gt;conda&lt;/a&gt; environment that is used by &lt;em&gt;all&lt;/em&gt; users. Everyone can read from it, but only users who are &lt;code&gt;admin&lt;/code&gt; can write to it (via &lt;code&gt;sudo&lt;/code&gt;). This is one of TLJH’s core design trade-offs - admins can install packages the way they are used to, without requiring a separate image-build step. But it also means the admin can mess it up - conda environments can be sometimes fickle! So it’s not a bad idea to spend some time in the beginning setting everything up - python packages, JupyterLab extensions, etc. Then make a disk snapshot, so you can revert to it if things go bad. This is where having a separate disk for your user home directories comes in handy, so you can reset your hub environment without losing your user home directories.&lt;/p&gt;
&lt;h2 id="ssh-admin-access"&gt;SSH admin access&lt;/h2&gt;
&lt;p&gt;The TLJH documentation strives hard to make sure SSH isn’t &lt;em&gt;required&lt;/em&gt; for setup and most common usage. However, if your TLJH breaks in certain ways, you can no longer access the machine — since all access is via TLJH! For this, I recommend making sure someone who is admin has SSH access to the VM. Most cloud providers offer a way to set the root ssh key on creation. If not, you can follow the many guides on the internet to making it happen.&lt;/p&gt;
&lt;p&gt;You can also just put your ssh keys in &lt;code&gt;$HOME/.ssh/authorized_keys&lt;/code&gt;, and ssh in as &lt;code&gt;jupyter-&amp;lt;username&amp;gt;@&amp;lt;hub-ip&amp;gt;&lt;/code&gt;. This works for any / all users!&lt;/p&gt;
&lt;h2 id="others"&gt;Others?&lt;/h2&gt;
&lt;p&gt;I’m sure this isn’t the end — probably need something about firewalls, monitoring and automated system package upgrades. But hey, great start!&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
</content><category term="JupyterHub"/><category term="TLJH"/></entry><entry><title>Lessons learned from Jupyter’s Contributor in Residence pilot</title><link href="https://blog.jupyter.org/posts/2021/lessons-learned-from-jupyters-contributor-in-residence/" rel="alternate"/><published>2021-03-11T20:22:00+00:00</published><updated>2021-03-11T20:22:00+00:00</updated><author><name>Georgiana Dolocan</name></author><id>tag:blog.jupyter.org,2021-03-11:/posts/2021/lessons-learned-from-jupyters-contributor-in-residence/</id><summary type="html">&lt;p&gt;Last year we ran the first iteration of the JupyterHub Contributor in Residence role. This post is a short report about what we learned, in the hopes that it guides other projects in pursuing similar programs.&lt;/p&gt;
</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;Project Jupyter, like most open source communities, often lacks the time and people power to maintain existing projects. Existing maintainers are often overloaded with work, while new volunteer contributions are often driven by the excitement of new feature development. Although on-boarding new maintainers is a sustained long-term team effort, it is something necessary and beneficial not only for the project, but also for existing maintainers and new contributors alike.&lt;/p&gt;
&lt;p&gt;For this reason, we decided to &lt;a href="https://blog.jupyter.org/posts/2019/the-jupyterhub-and-binder-contributor-in-residence/"&gt;pilot a Contributor in Residence&lt;/a&gt; program that was generously funded for a year through CZI’s &lt;a href="https://chanzuckerberg.com/eoss/"&gt;Essential Open Source Science program&lt;/a&gt;. Last year we ran the first iteration of the JupyterHub Contributor in Residence role. This post is a short report about what we learned, in the hopes that it guides other projects in pursuing similar programs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="tldr"&gt;tl;dr&lt;/h2&gt;
&lt;p&gt;The Contributor in Residence program is a great way to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introduce new members into your community&lt;/li&gt;
&lt;li&gt;Create pathways for others to get more experience, and grow in their role and leadership&lt;/li&gt;
&lt;li&gt;Get a lot of work done that is hard to motivate volunteers to do&lt;/li&gt;
&lt;li&gt;Spend time thinking at a “meta” level about how to improve dynamics in the community&lt;/li&gt;
&lt;li&gt;Have a paid opportunity to support individuals who can’t contribute via volunteerism alone&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, doing this well requires planning ahead of time and attention throughout the program. It is crucial that you develop a plan and pathways for integrating the CIR into your community, and ensuring that they have the right perspective to support the community. If you do this, the CIR program can be a fantastic win-win situation for everyone involved.&lt;/p&gt;
&lt;h2 id="what-is-the-contributor-in-residence"&gt;What is the Contributor in Residence?&lt;/h2&gt;
&lt;p&gt;The Contributor in Residence (CIR) carries out a variety of technical and community-focused actions, looking for opportunities to keep momentum moving forward in conversations, improving infrastructure to minimize human toil and streamline information, and making improvements to the codebase that are focused more around sustainability, stability, and understandability.&lt;/p&gt;
&lt;p&gt;For more information about our CIR program, check out these blog posts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.jupyter.org/posts/2019/the-jupyterhub-and-binder-contributor-in-residence/"&gt;CIR announcement post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.jupyter.org/posts/2020/cir-report-i/"&gt;CIR update post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=n07NDPbwdk8&amp;amp;t=1620s"&gt;Here’s a video of Georgiana talking about her experience&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img alt="The JupyterHub welcome bot image, hand-drawn by our first Contributor in Residence, Georgiana" src="https://blog.jupyter.org/posts/2021/lessons-learned-from-jupyters-contributor-in-residence/images/001-0_6hQJEAS34fJRY65r.jpg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The JupyterHub welcome bot image, hand-drawn by our first Contributor in Residence, Georgiana&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="how-management-and-planning-worked"&gt;How management and planning worked&lt;/h2&gt;
&lt;p&gt;We didn’t define explicit “metrics-based” outcomes for this Contributor in Residence pilot, as we were not sure the behaviors that would be most beneficial in the long-run. Instead, Georgiana kept track of the activities that she worked on throughout the year, and reflected with us often in identifying challenges to overcome, and opportunities to improve the work she was doing.&lt;/p&gt;
&lt;p&gt;In practice, Georgiana did not have a sole formal ongoing mentor providing her regular guidance throughout the project. She received mentorship from a variety of JupyterHub Team members across the repositories, and via participation in issues in GitHub (more on that later).&lt;/p&gt;
&lt;p&gt;Georgiana kept track of her actions &lt;a href="https://github.com/users/GeorgianaElena/projects/1"&gt;at this GitHub project&lt;/a&gt;. This contains a collection of issues, to-do items, and pull-requests throughout the JupyterHub community, and is a public record of much of the work that she focused on. While we scoped the CIR to cover all of the JupyterHub repositories, these efforts had a general focus on &lt;a href="https://github.com/jupyterhub/the-littlest-jupyterhub"&gt;The Littlest JupyterHub&lt;/a&gt;, where she is now the primary maintainer and community liaison for the project. In addition to these development-focused efforts, Georgiana also spent a lot of time improving infrastructure and team processes at the JupyterHub-wide level, generally via the &lt;a href="https://github.com/jupyterhub/team-compass"&gt;JupyterHub Team Compass&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="tips-for-running-a-cir-program"&gt;Tips for running a CIR program&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;The following are a few best-practices that we picked up during our pilot.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="define-an-explicit-work-plan-and-system-for-managing-tasks"&gt;Define an explicit work plan and system for managing tasks&lt;/h3&gt;
&lt;p&gt;The biggest challenge Georgiana faced was in identifying specific projects to work on, and working through the ambiguity of a position that explicitly had no single clear workstream. To get around this, Georgiana sought out guidance and advice from others in the community, and over time gained an understanding of ways that she could contribute. This will be a challenge for any Contributor in Residence moving forward, and we will need to think of new ways to support this role with concrete suggestions. Georgiana wrote a bit about this experience &lt;a href="https://blog.jupyter.org/posts/2020/cir-report-i/"&gt;in her CIR update blog post&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="dedicate-management-and-mentorship"&gt;Dedicate management and mentorship&lt;/h3&gt;
&lt;p&gt;A related challenge was in ensuring that the CIR felt like they had a clear idea of their expectations, to-do items, and progress. In future iterations, we would like to dedicate more resources towards providing mentorship and management of the person. This role shouldn’t be a “task giver,” but rather someone to help guide, triage, and prioritize for the benefit of the community. They should have regular touch-points with the CIR to make sure they are supported in their role.&lt;/p&gt;
&lt;h3 id="have-an-onboarding-session-to-help-them-navigate-your-project"&gt;Have an onboarding session to help them navigate your project&lt;/h3&gt;
&lt;p&gt;Regardless of ongoing mentorship, you should definitely have an onboarding session. Many open source communities have multiple projects, varying stages of contributor documentation, different spaces for conversation and interaction. Moreover, the technical infrastructure may have underlying architectures and organization that is hard to learn on your own. Have a core maintainer (or the mentor if you’re using one) go over your technology’s structure and layout, and double-check the things the CIR is unsure of, and introduce them to various discussions and action points to learn from. This may require multiple meetings in the first few weeks/months.&lt;/p&gt;
&lt;h3 id="assess-your-current-strategy-every-3-months-and-adjust-based-on-current-needs"&gt;Assess your current strategy every 3 months and adjust based on current needs&lt;/h3&gt;
&lt;p&gt;Choose a time interval when you revisit your plan. Project needs, community dynamics, and time availability will change over time, so take the time to think about what parts of the plan need to be modified to fit the situation at hand. An option could be bringing this up during team meetings to brainstorm ideas and get feedback, then write it down to put everything in order and make it real. Consider writing 3-month blog posts of your progress and status — these become public records of the experience gained from the program, and are good opportunities to reflect on how things are going.&lt;/p&gt;
&lt;h3 id="actively-invite-them-into-the-community"&gt;Actively invite them into the community&lt;/h3&gt;
&lt;p&gt;Remember that most open source communities are just that — communities. Take time to make sure others in the community know who the CIR is, invite them to participate in community conversations, welcome them in gitter/slack/issues/etc. Anything you can do to make them feel welcome is great. Make sure that you keep doing this over time, not just once at the beginning of their fellowship. When someone feels that they are welcome and a part of a community, they will be much more comfortable at navigating how to support it themselves.&lt;/p&gt;
&lt;h3 id="tailor-the-role-to-fit-the-cir-as-a-person-too"&gt;Tailor the role to fit the CIR as a person too&lt;/h3&gt;
&lt;p&gt;The CIR responsibilities are usually already sketched up before actually having a person to fill the role. Having an overall plan is an awesome idea and a very useful program compass. However, once the CIR is identified, it is important to re-address the overall focus and goals of the role to ensure that it aligns with the interests and skillsets of the incoming CIR. This includes things like familiarity with the project, future career directions for the CIR, and working styles for people involved.&lt;/p&gt;
&lt;h3 id="start-slower"&gt;Start slower&lt;/h3&gt;
&lt;p&gt;Jumping directly into a new project with a lot of complexity and many sub-projects is not sustainable. In our initial plan, we decided to track about 10 main repositories in the first three months of the CIR pilot. This was not sustainable, and led to an overwhelming feeling because of the constant influx of new issues, questions, etc. Especially for someone new to the community and their new role, this led to a feeling of “I’m not learning fast enough,” and difficulty concentrating on the plan. So please, start slow, take the time to acclimate to the project and go repository-by-repository.&lt;/p&gt;
&lt;h3 id="remember-that-knowing-everything-was-never-part-of-the-role"&gt;Remember that knowing everything was never part of the role&lt;/h3&gt;
&lt;p&gt;Being a CIR for a complex project can be very overwhelming. There may be different sub-projects, technology stacks, and team processes across a community. It is crucial to consider the CIR program as a two-way street — it is primarily a learning experience and a chance to grow for the CIR, as well as an opportunity for the project to get some much-needed assistance. The CIR &lt;strong&gt;should not be expected to know or do everything&lt;/strong&gt; either at the beginning or the end of their tenure — instead, celebrate the process and the learning that has come from it.&lt;/p&gt;
&lt;h2 id="ideas-for-things-the-cir-can-work-on"&gt;Ideas for things the CIR can work on&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Here are a few things that we found particularly useful for the CIR’s workstream, that will likely be portable across other communities as well.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="identify-automation-and-standardization-action-points"&gt;Identify automation and standardization action points&lt;/h3&gt;
&lt;p&gt;Observe whether a repetitive task could be performed by an automated system like a bot or a CI system, as this has the potential to ease the workload for maintainers.&lt;/p&gt;
&lt;p&gt;For example, the JupyterHub GitHub org has about 60 repositories. Some of them had issue and pull requests templates, but most of them didn’t. Some had instructions of how to make a new release of the project, others didn’t. Some had their instructions written in a &lt;em&gt;README&lt;/em&gt; and others had documentation, etc.&lt;/p&gt;
&lt;p&gt;When the CIR project took off, the JupyterHub and Binder team already started the quest of automating and standardizing its sub-projects. The CIR’s job was to help the other team members propagate the changes (bots setup, templates, badges, docs) to as many repositories as possible.&lt;/p&gt;
&lt;h3 id="research-and-discover-best-practices-from-other-communities"&gt;Research and discover best-practices from other communities&lt;/h3&gt;
&lt;p&gt;CIRs can also act as helpful eyes and ears to watch other communities and understand the practices that they adopt. Many practices are useful across projects, and a person serving in this “meta” role is in a good position to think at a high level about opportunities.&lt;/p&gt;
&lt;p&gt;For example — a simple “thank you” to a contributor can boost their experience a lot, especially when it is their first time contributing to a project. GitHub has a mechanism of letting you know when someone opens an issue or a PR to a project for the first time, but that little notification can be missed when under a huge load of work. For this, there is “the welcome bot” that can be set up to express the community’s gratitude towards their first time contributors.&lt;/p&gt;
&lt;p&gt;Our CIR noticed that “&lt;a href="https://the-turing-way.netlify.app/welcome"&gt;The Turing Way&lt;/a&gt;” — an open source community-driven guide to reproducible, ethical, inclusive and collaborative data science — made excellent use of GitHub’s welcome bot, including illustrations to make the message even more pleasant and celebratory. Georgiana was inspired by this, which led to adding welcome bots across the JupyterHub repository (including our own hand-drawn images!). Every time a contributor reacts with a ❤ to the bot’s message reinforces the feeling that the bot has its desired, positive effect.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Welcome images that Georgiana drew for the “welcome bots” that she deployed across the JupyterHub repositories." src="https://blog.jupyter.org/posts/2021/lessons-learned-from-jupyters-contributor-in-residence/images/002-0_WUb7phui0cNKOuL8.jpg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Welcome images that Georgiana drew for the “welcome bots” that she deployed across the JupyterHub repositories.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="spend-time-on-fixing-bugs-and-improving-testing-infrastructure"&gt;Spend time on fixing bugs and improving testing infrastructure&lt;/h3&gt;
&lt;p&gt;Having a working testing infrastructure helps maintainers and contributors alike. Various updates to the underlying infrastructure of the CI system, or even something as simple as a dependency version bump, can break it. So keeping an eye on the health of the testing infrastructure is something that should concern a CIR. This is particularly useful as the world of “maintenance automation” changes very rapidly, with new frameworks, plugins, and standards. Having a pair of eyes constantly thinking about how to improve this process is very helpful.&lt;/p&gt;
&lt;h3 id="share-maintainer-knowledge-by-improving-the-docs"&gt;Share maintainer knowledge by improving the docs&lt;/h3&gt;
&lt;p&gt;Having just a handful of people knowing how to to release a new version of a project is not scalable and puts an enormous pressure on that group. Instead, each project should have public instructions on how to do this, so that other contributors that have the permissions can cut a new project release.&lt;/p&gt;
&lt;p&gt;The process of creating &lt;em&gt;RELEASE.md&lt;/em&gt; files with these instructions for JupyterHub sub-projects, just like the standardization process, had already been started inside the JupyterHub org by the team members before the CIR started. The CIR’s job was to extend this idea to as many sub-projects as possible. This standardization and improvement quest continues to move forward thanks to the CIR and to Erik’s and Simon’s coordination efforts!&lt;/p&gt;
&lt;p&gt;More generally — the CIR is often someone relatively new to a project, which makes them a valuable perspective to understand where team documentation is unclear to newcomers. Use the fresh eyes of the CIR to understand how to make the project more welcoming and easy to navigate, and it will clear a pathway for more to join the project in the future.&lt;/p&gt;
&lt;h2 id="what-we-still-havent-figured-out"&gt;What we still haven’t figured out&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;While we learned a lot during this pilot phase, there are a few things we still haven’t figured out.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="how-to-define-a-pipeline-for-new-cirs"&gt;How to define a pipeline for new CIRs&lt;/h3&gt;
&lt;p&gt;The tenure of a CIR seems like it will be relatively short — maybe one to two years on average. This means that we need a pipeline of new individuals that are ready to learn and take on this role once a previous CIR moves on. Being effective as a CIR was only possible for someone with some context for the JupyterHub repositories and team processes, and we likely would not have had success hiring someone on a one-year contract who had never worked in the JupyterHub community before. In future iterations we will need a reliable pipeline of newcomers to the project to potentially serve as CIRs. Programs like Outreachy and Google Summer of Code are excellent sources of future CIRs, but we need to think about the “pipeline” for gracefully using them to power the CIR project.&lt;/p&gt;
&lt;h3 id="find-mentorship-that-isnt-nights-and-weekends"&gt;Find mentorship that isn’t “nights and weekends”&lt;/h3&gt;
&lt;p&gt;While we may be able to find funding for mentorship and management, many people in the JupyterHub community already had full-time jobs. Having funding to pay for a part of someone’s time is helpful, but this is only possible if you can actually buy out part of somebody’s time (often not possible in certain careers and roles). It may be possible to spend extra time on mentorship in the evenings and weekends, but a sustainable model for this program will require somebody dedicating part of their “FTE time” on mentorship. We need to identify certain kinds of roles / individuals that have this flexibility in their work-load, and bake it into the strategy of the program.&lt;/p&gt;
&lt;h3 id="define-a-funding-mechanism-for-cirs"&gt;Define a funding mechanism for CIRs&lt;/h3&gt;
&lt;p&gt;Finally, this CIR pilot was funded by a one-year grant from CZI. In future iterations we will need to have a strategy for funding this position in a reliable manner (or at least, in a repeatable manner). To make this sustainable, we must define a pattern to follow and require resources to do a good job. This will both reduce the amount of effort needed to plan a new round for the CIR, and will make it easier for other organizations to understand how their financial contributions could help fund another round of the program. Perhaps this can be an ongoing fundraising effort, similar to how other programs have “target funding levels” in their annual giving strategy, or perhaps it can be a coordinated effort across projects to join resources together for these positions. Either way, it will be important to have reliable funding to ensure that the CIR program isn’t in a constant state of sputtering and jumpstarting.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We hope that this post was an informative and useful set of lessons-learned from the JupyterHub team. If you’ve got any suggestions, comments, or questions for us, we’d love to chat. Feel free to open up an issue in &lt;a href="http://discourse.jupyter.org"&gt;the Jupyter Community Forum&lt;/a&gt;! We look forward to continuing this experiment, and hope to see other communities experimenting with the same model in the future.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
</content><category term="community"/><category term="diversity"/><category term="JupyterHub"/></entry><entry><title>Plasma: A learning platform powered by Jupyter</title><link href="https://blog.jupyter.org/posts/2020/plasma-a-learning-platform-powered-by-jupyter/" rel="alternate"/><published>2020-05-11T07:55:00+00:00</published><updated>2020-05-11T07:55:00+00:00</updated><author><name>Jeremy Tuloup</name></author><id>tag:blog.jupyter.org,2020-05-11:/posts/2020/plasma-a-learning-platform-powered-by-jupyter/</id><summary type="html">&lt;p&gt;Jupyter has been a great choice for education for many years. The Jupyter Notebook has become one of the most popular tools to conduct workshops, tutorials, and teach online classes.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Jupyter has been a &lt;a href="https://blog.jupyter.org/posts/2019/teaching-and-learning-with-jupyter/"&gt;great choice&lt;/a&gt; for &lt;a href="https://jupyter4edu.github.io/jupyter-edu-book/"&gt;education&lt;/a&gt; for many years. The Jupyter Notebook has become one of the most popular tools to conduct workshops, tutorials, and teach online classes.&lt;/p&gt;
&lt;p&gt;Recently we have seen the emergence and adoption of JupyterHub distributions to facilitate the deployment of Jupyter-based platforms, both on private servers and in the cloud.&lt;/p&gt;
&lt;p&gt;We would like to share with you an open-source learning platform called &lt;a href="https://twitter.com/PlasmaBio"&gt;Plasma&lt;/a&gt;, built with Jupyter at its core.&lt;/p&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2020/plasma-a-learning-platform-powered-by-jupyter/images/001-0_wWdglu7KBVC08Lcc.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;h2 id="jupyterhub-distributions"&gt;JupyterHub Distributions&lt;/h2&gt;
&lt;p&gt;JupyterHub is a highly customizable and modular framework. To simplify its adoption, &lt;a href="https://jupyterhub.readthedocs.io/en/stable/#jupyterhub"&gt;JupyterHub distributions&lt;/a&gt; target specific deployment scenarios with opinionated defaults. They make it easier to deploy JupyterHub on a single server and in the cloud.&lt;/p&gt;
&lt;p&gt;There are currently two popular JupyterHub distributions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://tljh.jupyter.org"&gt;The Littlest JupyterHub (TLJH)&lt;/a&gt;: for running JupyterHub on a single machine, targeting between 1 and 100 users&lt;/li&gt;
&lt;li&gt;&lt;a href="https://zero-to-jupyterhub.readthedocs.io"&gt;Zero To JupyterHub on Kubernetes (ZTJH)&lt;/a&gt;: for running JupyterHub on top of &lt;a href="https://k8s.io/"&gt;Kubernetes&lt;/a&gt;, to scale to a large number of users and machines&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Although not an official distribution, &lt;a href="https://github.com/jupyterhub/jupyterhub-deploy-docker"&gt;jupyterhub-deploy-docker&lt;/a&gt; is also a good resource for a full Docker-based setup. It runs JupyterHub itself in a Docker container and orchestrates the stack with &lt;a href="https://docs.docker.com/compose/"&gt;Docker Compose&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="the-plasma-stack"&gt;The Plasma Stack&lt;/h2&gt;
&lt;p&gt;Plasma stands for &lt;em&gt;PLateforme d’e-Learning pour l’Analyse de données Scientifiques MAssives&lt;/em&gt;, which can be translated to “An e-learning platform for massive scientific data analysis”.&lt;/p&gt;
&lt;p&gt;The platform is typically meant to be deployed on high-end machines with multiple cores and GB of RAM.&lt;/p&gt;
&lt;p&gt;Some of the requirements for the Plasma project fall somewhere between the TLJH and ZTJH distributions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The deployment should be on a single server, and reproducible on other machines too (running on Ubuntu 18.04+)&lt;/li&gt;
&lt;li&gt;It should support multiple user environments with different sets of dependencies&lt;/li&gt;
&lt;li&gt;Users should authenticate as system users and their data should be persisted in their home directories on the host machine&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Although TLJH doesn’t officially support container technology, its &lt;a href="http://tljh.jupyter.org/en/latest/contributing/plugins.html"&gt;plugin system&lt;/a&gt; opens the door to many other use cases.&lt;/p&gt;
&lt;p&gt;Because of this and to foster the TLJH plugin ecosystem, we decided to develop the Plasma stack as a plugin for TLJH and consolidate the deployment story with Ansible playbooks.&lt;/p&gt;
&lt;p&gt;Plasma is an opinionated JupyterHub stack powered by The Littlest JupyterHub, with the following defaults:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jupyterhub.readthedocs.io/en/stable/api/auth.html#pamauthenticator"&gt;PAMAuthenticator&lt;/a&gt; to authenticate JupyterHub as users existing on the host machine&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jupyterhub/dockerspawner#systemuserspawner"&gt;SystemUserSpawner&lt;/a&gt; to start single-user servers in Docker containers, using the system user home directories for data persistence&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To enable extra functionalities, the Plasma stack relies on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://github.com/plasmabio/tljh-repo2docker"&gt;tljh-repo2docker&lt;/a&gt; plugin to create multiple user environments&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://github.com/plasmabio/plasma/tree/master/tljh-plasma"&gt;tljh-plasma&lt;/a&gt; plugin to define the JupyterHub config&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/plasmabio/plasma/tree/master/ansible"&gt;Ansible playbooks&lt;/a&gt; to automate the deployment and configuration of the server and add additional tools&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Plasma stack also contains tools to monitor the system, create and configure users, and add hub admins. It can be visualized with the diagram below:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="The Plasma Overview Diagram" src="https://blog.jupyter.org/posts/2020/plasma-a-learning-platform-powered-by-jupyter/images/002-1_r-RSTILR7yfT7By30eaeTg.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The Plasma Overview Diagram&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The stack is defined in the following repository: &lt;a href="https://github.com/plasmabio/plasma"&gt;https://github.com/plasmabio/plasma&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There is also extensive documentation with detailed explanations on how to deploy the stack on a new server: &lt;a href="https://docs.plasmabio.org"&gt;https://docs.plasmabio.org&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="a-repo2docker-plugin-for-the-littlest-jupyterhub"&gt;A repo2docker plugin for The Littlest JupyterHub&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://github.com/plasmabio/tljh-repo2docker"&gt;tljh-repo2docker&lt;/a&gt; plugin lets JupyterHub admins create new user environments using &lt;a href="https://repo2docker.readthedocs.io"&gt;repo2docker&lt;/a&gt;. This plugin starts a &lt;a href="https://jupyterhub.readthedocs.io/en/stable/reference/services.html"&gt;JupyterHub service&lt;/a&gt; to manage user environments from the JupyterHub UI.&lt;/p&gt;
&lt;p&gt;For those already using &lt;a href="https://mybinder.org"&gt;Binder&lt;/a&gt;, the idea will sound very familiar. Under the hood, the tljh-repo2docker plugin also uses &lt;a href="https://repo2docker.readthedocs.io/en/latest/"&gt;repo2docker&lt;/a&gt; to build the Docker images. It follows the same patterns and naming conventions as Binder, which makes it easier and more natural to test the environments on Binder before adding them to JupyterHub.&lt;/p&gt;
&lt;p&gt;New environments can be added by clicking on the &lt;em&gt;Add New&lt;/em&gt; button and providing a URL to the repository. Optional names, memory, and CPU limits can also be set for the environment:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Adding a new environment" src="https://blog.jupyter.org/posts/2020/plasma-a-learning-platform-powered-by-jupyter/images/003-1_KMOJ3287DPh6aG8Kg4EkEg.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Adding a new environment&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;em&gt;Environments&lt;/em&gt; page shows the list of built environments, as well as the ones currently being built:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Building a new environment" src="https://blog.jupyter.org/posts/2020/plasma-a-learning-platform-powered-by-jupyter/images/004-1_VpXTXOEt4Owlf5O713ktLw.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Building a new environment&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The status of the environment changes once the underlying Docker image has been built:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="The list of available user environments" src="https://blog.jupyter.org/posts/2020/plasma-a-learning-platform-powered-by-jupyter/images/005-1_uHAYqgSCAfswFXvRHTO43w.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The list of available user environments&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Once ready, the environments can be selected from the JupyterHub spawn page:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Selecting an environment" src="https://blog.jupyter.org/posts/2020/plasma-a-learning-platform-powered-by-jupyter/images/006-0_nOCNtzHaQ_dj3-Jg.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Selecting an environment&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Because it is separate from the Plasma stack, this plugin can also be used for other temporary TLJH deployments on a virtual machine. For example, the organizer of a workshop can prepare a list of environments before the event, just like they would with Binder.&lt;/p&gt;
&lt;h2 id="automating-deployments-with-ansible"&gt;Automating deployments with Ansible&lt;/h2&gt;
&lt;p&gt;To minimize the number of manual steps involved in the setup of the stack, Plasma also provides a list of &lt;a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks.html"&gt;Ansible playbooks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.ansible.com/ansible/latest/index.html"&gt;Ansible&lt;/a&gt; is an open-source tool to automate the provisioning of servers, configuration management, and application deployment.&lt;/p&gt;
&lt;p&gt;Playbooks define a list of tasks that should be executed and declare the desired state of the server.&lt;/p&gt;
&lt;p&gt;The list of playbooks and instructions on how to use them are provided in the &lt;a href="https://docs.plasmabio.org/en/latest/install/index.html"&gt;Installation section of the documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Overall, the playbooks make it easier to perform upgrades, to automate the deployment process, and to replicate the setup at other institutions and universities.&lt;/p&gt;
&lt;p&gt;Here is an example of what an upgrade looks like:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Upgrading the stack with an Ansible playbook" src="https://blog.jupyter.org/posts/2020/plasma-a-learning-platform-powered-by-jupyter/images/007-1_0n1kaev7c81I45SZ0HoLxQ.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Upgrading the stack with an Ansible playbook&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This playbook defines the tasks to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;download the TLJH installer&lt;/li&gt;
&lt;li&gt;execute the TLJH installer to perform the upgrade&lt;/li&gt;
&lt;li&gt;update the TLJH plugins&lt;/li&gt;
&lt;li&gt;set the idle culler timeout&lt;/li&gt;
&lt;li&gt;set the default memory and CPU limits&lt;/li&gt;
&lt;li&gt;reload JupyterHub&lt;/li&gt;
&lt;li&gt;pulls the latest &lt;code&gt;jupyter/repo2docker&lt;/code&gt; Docker image&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="further-reading"&gt;Further reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The Plasma documentation: &lt;a href="https://docs.plasmabio.org/"&gt;https://docs.plasmabio.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;To use the tljh-repo2docker as a standalone plugin for TLJH: &lt;a href="https://github.com/plasmabio/tljh-repo2docker"&gt;https://github.com/plasmabio/tljh-repo2docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Also part of the Plasma project, the new &lt;a href="https://github.com/QuantStack/ipycytoscape"&gt;ipycytoscape&lt;/a&gt; package for interactive graph visualization in Jupyter: &lt;a href="https://blog.jupyter.org/posts/2020/interactive-graph-visualization-in-jupyter-with/"&gt;Interactive Graph Visualization in Jupyter with ipycytoscape&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
&lt;h2 id="acknowledgements"&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;The development of the Plasma stack at &lt;a href="https://quantstack.net/"&gt;QuantStack&lt;/a&gt; was funded as part of the &lt;a href="https://twitter.com/PlasmaBio"&gt;Plasma&lt;/a&gt; project, led by &lt;a href="https://twitter.com/CVandiedonck"&gt;Claire Vandiedonck&lt;/a&gt;, &lt;a href="https://twitter.com/pierrepo"&gt;Pierre Poulain&lt;/a&gt;, and &lt;a href="https://twitter.com/SCaburet"&gt;Sandrine Caburet&lt;/a&gt;, associate professors at Université de Paris.&lt;/p&gt;
&lt;p&gt;Sponsors to the Plasma initiative include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://twitter.com/iledefrance"&gt;Région Île-de-France&lt;/a&gt;, via the “Trophées franciliens de l’innovation numérique dans le supérieur” (&lt;a href="https://www.iledefrance.fr/trophees-franciliens-de-linnovation-numerique-dans-le-superieur-les-laureats-2018"&gt;EdTech 2018&lt;/a&gt;) grant program,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/Univ_Paris"&gt;Université de Paris&lt;/a&gt;, via the &lt;a href="https://u-paris.fr/en/the-initiative-of-excellence-idex-label/"&gt;Initiative of Excellence (IdEx) Label&lt;/a&gt; and its “inovating teaching” grant program,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/EURGENEPARIS"&gt;EUR G.E.N.E.&lt;/a&gt;, the graduate school on Genetics and Epigenetics,&lt;/li&gt;
&lt;li&gt;the university training “Création, analyse et valorisation de données biologiques omiques” (&lt;a href="https://omics-school.net/"&gt;DU Omiques&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
</content><category term="education"/><category term="JupyterHub"/><category term="repo2docker"/><category term="TLJH"/></entry><entry><title>The Jupyter Contributor In Residence, update 1</title><link href="https://blog.jupyter.org/posts/2020/cir-report-i/" rel="alternate"/><published>2020-05-07T15:22:00+00:00</published><updated>2020-05-07T15:22:00+00:00</updated><author><name>Georgiana Dolocan</name></author><id>tag:blog.jupyter.org,2020-05-07:/posts/2020/cir-report-i/</id><summary type="html">&lt;p&gt;The JupyterHub and Binder Contributor in Residence. The first &lt;a href="https://en.wikipedia.org/wiki/Keepalive"&gt;keepalive message&lt;/a&gt;.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;em&gt;This year Jupyter was awarded a one-year “&lt;a href="https://chanzuckerberg.com/eoss/"&gt;Essential Open Source Software for Science&lt;/a&gt;” grant from the &lt;a href="https://chanzuckerberg.com/"&gt;Chan Zuckerberg Initiative&lt;/a&gt;, which we are using to bring on our first “Contributor in Residence” (many thanks, CZI ❤). This is a short report back from Jupyter’s first “&lt;a href="https://blog.jupyter.org/posts/2019/the-jupyterhub-and-binder-contributor-in-residence/"&gt;Contributor in Residence&lt;/a&gt;”, &lt;a href="https://github.com/GeorgianaElena"&gt;Georgiana Dolocan&lt;/a&gt;. We are now about one third of the way through her tenure as CIR. Editor’s note: Georgiana has also made all of her own GIFs, because she’s just awesome like that ;-)&lt;/em&gt;&lt;/p&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2020/cir-report-i/images/001-1_vCYZLSCYhI4XGm8pZG-okw.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;At the end of last year, I found out that the &lt;a href="https://blog.jupyter.org/posts/2019/the-jupyterhub-and-binder-contributor-in-residence/"&gt;CZI grant&lt;/a&gt; (so nicely put together by Chris Holdgraf), was accepted. I was very happy to have gotten the chance to continue working alongside an amazing community that I grew very fond of from day one that I started contributing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="plan-10"&gt;Plan 1.0&lt;/h2&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2020/cir-report-i/images/002-1__GNG9croNBQjsCLGO-riNA.mp4" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;Being the first project of its kind, we had millions of ideas about what the Contributor in Residence (CIR) project should be about. We discussed and converged towards a common plan, then we decided to continuously iterate once we got some real life feedback.&lt;/p&gt;
&lt;p&gt;See &lt;a href="https://github.com/jupyterhub/team-compass/issues/237"&gt;this GitHub issue&lt;/a&gt; with the end result of the brainstorming, and with various milestones set in place. In short, the purpose of the CIR is to work on the little day-to-day tasks that occur across a project (respond to questions, review PRs, fix bugs, write documentation, maintain infrastructure), nothing fancy, no big projects.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-biggest-little-achievements"&gt;The biggest little achievements&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Among the little day-to-day tasks, there are a few achievements that are more noticeable and worthwhile to mention, that will potentially have a bigger impact than others.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="the-first-blog-post-about-the-littlest-jupyterhub-is-out"&gt;🚩 The first blog post about The-Littlest-JupyterHub is out&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://blog.jupyter.org/posts/2020/the-superheroes-and-the-magic-wand/"&gt;&lt;em&gt;The superheroes and the magic wand&lt;/em&gt;&lt;/a&gt; is the first blog post about TLJH on the Jupyter Blog. It first started as a technical blog post but while writing and constantly relating to TLJH as having superpowers to explain how it works, it turned rapidly into a superhero story.&lt;/p&gt;
&lt;p&gt;TLJH is an important project in the Jupyter ecosystem and one that I care about a lot, so stay tuned as there are more blog posts to come about it, and although technical this time, I won’t restrain myself from talking about its superpowers.&lt;/p&gt;
&lt;h3 id="the-tljh-ci-tests-were-refactored-and-an-upgrade-test-was-added"&gt;🚩 The TLJH CI tests were refactored and an upgrade test was added&lt;/h3&gt;
&lt;p&gt;Are you familiar with that feeling when a pull request looks OK, it passes all tests and all the bots are happy, so you hit that merge button? Yet, soon after, the unexpected happens and bug reports start showing up. 🙈&lt;/p&gt;
&lt;p&gt;Even though you manage to find the issue and solve it, one question remains: “Why did the checks pass?” The answer isn’t easy to hear: “The tests need to be improved”.&lt;/p&gt;
&lt;p&gt;TLJH operates on a “rolling release” model, where people just install from master, so it’s very important to have strong tests. However, our issue wasn’t exactly with the tests themselves, but rather our &lt;a href="https://github.com/jupyterhub/the-littlest-jupyterhub/issues/503"&gt;CI didn’t match the production installation workflow&lt;/a&gt;, and that small difference between the workflows left TLJH in an uninstallable state. Merging that PR in the first place along with finding the divergence point was the key to solve the problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bonus point&lt;/strong&gt;: whenever someone wants to upgrade TLJH, they do it by running the installer again. Thus, the changes we’re adding by merging a PR, don’t just need to pass the tests, but also they must not break the upgrade process. So, we also added an &lt;a href="https://github.com/jupyterhub/the-littlest-jupyterhub/pull/511"&gt;upgrade test to our CI&lt;/a&gt; to solve any potential future upgrade problems.&lt;/p&gt;
&lt;h3 id="three-repositories-in-the-jupyterhub-organization-are-now-being-watched-by-a-support-bot"&gt;🚩 Three repositories in the JupyterHub organization are now being watched by a support bot&lt;/h3&gt;
&lt;p&gt;The Jupyter community currently uses GitHub, &lt;a href="https://gitter.im/jupyterhub/jupyterhub"&gt;Gitter&lt;/a&gt; and &lt;a href="https://discourse.jupyter.org/"&gt;Discourse&lt;/a&gt; (the newest of them) to connect to one another. Having three communication channels might be confusing if there isn’t any clear distinction between them in terms of their scope. So we needed to find a way to organize our discussion to make the contributing experience better for everyone (users, core developers, and everyone in between).&lt;/p&gt;
&lt;p&gt;The &lt;a href="http://discourse.jupyter.org"&gt;Discourse forum&lt;/a&gt; was already the place where most of our general discussions happened. So why not make this place even more popular and encourage everybody to share their ideas and questions there? This way, the forum becomes the place where we can help and inspire each-other, and GitHub issues are where we talk about cool new features, find bugs, and figure out how to solve the issues.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/apps/support"&gt;support bot&lt;/a&gt; will help spread the word about the forum and will make the transition easier. Currently, it is plugged into the &lt;a href="https://github.com/jupyterhub/jupyterhub"&gt;jupyterhub&lt;/a&gt;, &lt;a href="https://github.com/jupyterhub/binderhub"&gt;binderhub&lt;/a&gt; and &lt;a href="https://github.com/jupyterhub/the-littlest-jupyterhub"&gt;tljh&lt;/a&gt; repositories and will act each time the “support” label is added to a GitHub issue that should be on Discourse.&lt;/p&gt;
&lt;p&gt;We kindly encourage everybody to use Discourse to start or participate in awesome discussions or ask questions of any kind. A great place to start is the &lt;a href="https://discourse.jupyter.org/t/introduce-yourself/17/131"&gt;&lt;em&gt;Introduce yourself&lt;/em&gt; thread&lt;/a&gt; where you can just stop by and say “Hi”.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="struggles-and-solutions"&gt;Struggles and solutions&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Working on little tasks sounds simpler and easier than starting a big, complex project from scratch. Well, this is not entirely true… Those small tasks are happening around big projects that are used by a lot of people and are constantly evolving. So, even a small, not very complicated task, can be hard when you’re still figuring out the “hows” and “wheres” of a project.&lt;/em&gt;&lt;/p&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2020/cir-report-i/images/003-1_qaJ2OXcIQc9qeHDhH4ZUyw.mp4" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;h3 id="struggle-distributing-focus-across-multiple-repositories-and-issues"&gt;Struggle: distributing focus across multiple repositories and issues&lt;/h3&gt;
&lt;p&gt;When working on a bigger project, I used to switch between tasks as a means to unwind when running out of ideas and things seemed impossible. I guess one could call this multitasking. However, switching between tasks of different projects that you know little about is challenging enough to cause stress, resuscitate that impostor syndrome, and ultimately turn into burnout.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Although I don’t have a solution to this and I’m still having troubles mastering this skill, I find inspiration and hope among the people in the Jupyter community. Even if maintaining lots of projects at once, they manage to successfully juggle between tasks, sometimes even when this isn’t their main job, so they deserve a huge shout out ❤️&lt;/p&gt;
&lt;h3 id="struggle-keeping-track-of-little-things"&gt;Struggle: keeping track of little things&lt;/h3&gt;
&lt;p&gt;The difference between working on a big project and solving small tasks here and there (besides the obvious size distinction) is that solving smaller tasks makes you prone to loosing a sense of progress. Though not a project in the traditional way, the CIR is a concept that would be worth extending if successful, so evaluating its progress is a must and can help determine and improve those weak points — and why not — even point out when it’s time to stop. But keeping track of little things is tricky.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: GitHub issues, comments or PRs can automatically be retrieved through GitHub’s API (Chris Holdgraf has a great tool for this called &lt;a href="https://github.com/choldgraf/github-activity"&gt;github-activity&lt;/a&gt;). However, to get a sense of accomplishment and progress at the end of the day, I tried to keep my own list of todos and tasks done. I experimented with two approaches in this sense: keeping a HackMD “journal” and creating a &lt;a href="https://github.com/users/GeorgianaElena/projects/1"&gt;GitHub project&lt;/a&gt;. After these three months I think I like the GitHub project better because it allows me to keep a todo list with small enhancements I’d like to work when that notification bell doesn’t ring that often and it’s less copy and pasting links.&lt;/p&gt;
&lt;h3 id="struggle-getting-out-of-the-comfort-zone"&gt;Struggle: getting out of the comfort zone&lt;/h3&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2020/cir-report-i/images/004-1_7IYmviNQrZQtsDBcx95-9Q.mp4" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;Implementing that cool new feature or solving that annoying bug when feeling adventurous are part of the fun of software development. However, being a CIR is more than writing code. Things like writing blog posts and reviewing PRs are core responsibilities as well. But these are all new territory, so much that, I think up until last year I could count on the fingers of one hand the number of blog posts I had written or the number of PRs I had reviewed. So, the only thing left to say is “Hello new challenges! Farewell comfort zone 👋”.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Accept the challenge and practice every day until things don’t feel that scary anymore. Patience is key.&lt;/p&gt;
&lt;h2 id="plan-20"&gt;Plan 2.0&lt;/h2&gt;
&lt;p&gt;Version 1 of the plan was solid enough not to have to modify it completely.&lt;br&gt;
So, things like tracking down the bugs and failing tests won’t be halted.&lt;br&gt;
Instead, during these next two months, the plan will only suffer some little focus-related adjustments.&lt;/p&gt;
&lt;p&gt;Specifically, I want to focus more on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Getting more familiar with some of the repositories that didn’t get enough attention during the first phase of the project (&lt;a href="http://github.com/jupyterhub/zero-to-jupyterhub-k8s"&gt;zero-to-jupyterhub-k8s&lt;/a&gt;, &lt;a href="http://github.com/jupyterhub/jupyterhub-deploy-docker"&gt;jupyterhub-deploy-docker&lt;/a&gt;, &lt;a href="http://github.com/jupyterhub/binderhub"&gt;binderhub&lt;/a&gt;, &lt;a href="http://github.com/jupyterhub/dockerspawner"&gt;dockerspawner&lt;/a&gt;, &lt;a href="http://github.com/jupyterhub/kubespawner"&gt;kubespawner&lt;/a&gt;, &lt;a href="http://github.com/jupyter/repo2docker"&gt;repo2docker&lt;/a&gt;), potentially improving the documentation along the way. No more dipping the toes in the water, just dive in 🌊.&lt;/li&gt;
&lt;li&gt;Writing more blog posts about the superpowers of TLJH.&lt;/li&gt;
&lt;li&gt;Have more bots 🤖 helping the community.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the process, I hope I can check the boxes for some of the items on my “learn and improve” wish-list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;technical writing&lt;/li&gt;
&lt;li&gt;Kubernetes&lt;/li&gt;
&lt;li&gt;UI/UX&lt;/li&gt;
&lt;li&gt;courage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Stay tuned, because the next blog post about the JupyterHub and Binder Contributor in Residence adventures should be out in two months time.&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
</content><category term="Binder"/><category term="community"/><category term="JupyterHub"/></entry><entry><title>The superheroes and the magic wand</title><link href="https://blog.jupyter.org/posts/2020/the-superheroes-and-the-magic-wand/" rel="alternate"/><published>2020-03-19T18:23:00+00:00</published><updated>2020-03-19T18:26:00+00:00</updated><author><name>Georgiana Dolocan</name></author><id>tag:blog.jupyter.org,2020-03-19:/posts/2020/the-superheroes-and-the-magic-wand/</id><summary type="html">&lt;p&gt;This is the first of a series of posts describing tools in the JupyterHub ecosystem, written by our wonderful Contributor in Residence, Georgiana. For our first post, we’ll share some lore of JupyterHub, and tell you a story of how it all began…&lt;/p&gt;</summary><content type="html">&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2020/the-superheroes-and-the-magic-wand/images/001-1_v9JBClFvN4V-YZOQgwNxig.mp4" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is the first of a series of posts describing tools in the JupyterHub ecosystem, written by our wonderful &lt;em&gt;Contributor in Residence&lt;/em&gt;, Georgiana. For our first post, we’ll share some lore of JupyterHub, and tell you a story of how it all began…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In a place far, far away, on a planet called Jupyter, magic happens every day. This land is special because it’s full of magical tools with all kind of powers, devoted to one common purpose: to help people. Everyone sympathizing with this goal either advocates, uses, or cares for these tools. So, in the blink of an eye, these people with sometimes nothing else in common than the same drive to help others, gathered together and formed a community.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This special group is known in the galaxy as “&lt;strong&gt;The Jovyans&lt;/strong&gt;” and new recruits join every day.&lt;/em&gt; 🚀&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;
&lt;img alt="This image was created by Scriberia for The Turing Way community and is used under a CC-BY licence. Zenodo record." src="https://blog.jupyter.org/posts/2020/the-superheroes-and-the-magic-wand/images/002-1_lz2yH1jyAlILFF9hZNtFPg.jpeg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;This image was created by &lt;a href="http://www.scriberia.co.uk/"&gt;Scriberia&lt;/a&gt; for &lt;a href="https://github.com/alan-turing-institute/the-turing-way"&gt;&lt;strong&gt;The Turing Way&lt;/strong&gt;&lt;/a&gt; community and is used under a CC-BY licence. &lt;a href="https://zenodo.org/record/3695300"&gt;Zenodo record&lt;/a&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;But somebody needed to take care of these magical tools. So, the first Jovyans decided that from then on, they will become tool-keepers. Because their greatest responsibility was to teach new Jovyans how to use the magic, shortly after, they created a set of guiding laws. Some call this &lt;em&gt;“the&lt;/em&gt; &lt;em&gt;&lt;strong&gt;Documentation&lt;/strong&gt;&lt;/em&gt;”.&lt;/p&gt;
&lt;h2 id="the-magic-wand"&gt;The magic wand&lt;/h2&gt;
&lt;p&gt;One greatly cherished tool on planet Jupyter is the magical wand. This wand’s very special power is to help people work together as a team and find solutions to important problems.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The wand is called “&lt;strong&gt;JupyterHub&lt;/strong&gt;”.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2020/the-superheroes-and-the-magic-wand/images/003-1_3nDwvUQiUfa54OsDPqKNag.mp4" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;But the wand is of vast complexity and because of this, so are the guiding laws that control it.&lt;/p&gt;
&lt;p&gt;As a consequence, people trying to benefit from the magic of JupyterHub, spent a lot of time reading and understanding the instructions.&lt;/p&gt;
&lt;h2 id="the-superheros"&gt;The superheros&lt;/h2&gt;
&lt;p&gt;The tool-keepers noticed that most of the people coming to planet Jupyter to become Jovyans were from a big city in the cloud 🌤 called &lt;em&gt;Kubernetes&lt;/em&gt;. So they gathered together and debated what is the best way to help the people of Kubernetes.&lt;/p&gt;
&lt;p&gt;After 3 days and 3 nights of intense discussions (also lots of pizza breaks of course) they decided that one of them needed to get special training, rent a house in Kubernetes and teach the people there the wonders of the JupyterHub magic wand.&lt;/p&gt;
&lt;p&gt;The Chosen One gained the people’s trust, and it got better and better at anticipating and understanding their needs. So the locals started seeing it as a superhero and they even gave it a name, “&lt;strong&gt;Z2JH&lt;/strong&gt;”. 👓&lt;/p&gt;
&lt;p&gt;The news of these events started to spread far and wide, and people living in little towns outside of Kubernetes felt that they deserved the support of a superhero too. They also had great ideas and little time and needed to use the wand’s magic to do good.&lt;/p&gt;
&lt;p&gt;The tool-keepers were inspired by the magnificent accomplishments of these little towns, taking place even without a superhero around. So the littlest of them all, volunteered to go into superhero training to help the people of the little towns do good, faster. Though it was little, in no time, it grew to become the helper these small groups needed.&lt;/p&gt;
&lt;p&gt;The residents called it “&lt;strong&gt;The Littlest JupyterHub” or “TLJH”&lt;/strong&gt; because of its stature. But everybody knew that its stature didn’t reflect its enormous tenacity, speed and ability to do great things. This ended up inspiring people all over to believe that not all superheros wear capes, nor do they need to know how to fly in the cloud to be cool.&lt;/p&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2020/the-superheroes-and-the-magic-wand/images/004-1_egrzbBcwyaxm7-793O7uiQ.mp4" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nowadays, people from all over join their forces and help the superheros learn new skills. Thanks to them, TLJH and Z2JH get stronger and better and have more special powers than they had when first created by the tool-keepers. Join them, become a Jovyan! ツ&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
</content><category term="JupyterHub"/><category term="Kubernetes"/><category term="TLJH"/></entry></feed>