Recently, I’ve been on a search for interactive runbooks. My team has several use-cases for such a tool including:

  • repeatable, runnable procedures
  • a REST book that can be used to query and validate APIs
  • to document complex API integrations

First, a bit about my team. We’re globally-distributed, and maintain a growing number of microservices built mostly using Mulesoft, but with some AWS services, Drupal, and Symfony in the mix. We’ve been transitioning to Mulesoft and API-led strategy from a mostly PHP-based fleet of apps. This means there’s a good deal of PHP knowledge, along with several other languages and technologies (Go, Java, Dataweave, JavaScript, SQL, Python, BASH).

Available Tools

There are a growing number of tools that provide runbook functionality, and there are tradeoffs with each option. Some of the current tools in the runbook category include VS Code Custom Notebooks, Elixir Livebook, Jupyter Notebook, and Emacs org-mode. Below is a table comparing some of the characteristics of each option.

Trait / ToolVS Code Custom NotebooksElixir LivebookJupyter NotebookEmacs org-mode
Supported TechPluggableElixir/ErlangPythonPolyglot
FormatJSONMarkdownJSONOrg Markup
Human ReadableNoYesNoYes
GitHub ReadableNoYesYesYes
SoftwareVS Code Insiders + PluginElixir LivebookJupyter NotebookEmacs

Criteria Breakdown

The criteria that are most important to my team (not necessarily in this order):

  1. readability as plain text
  2. ease of install and setup
  3. minimal friction to adopt
  4. can execute the technologies we use

Readability as plain text

This means we don’t need to rely on any special technology to use a runbook - we can easily read the runbook and perform the necessary steps to fulfill the requirements of a procedure. Elixir Livebook and Emacs org-mode both meet this criteria.

Ease of install and setup

VS Code Custom Notebooks requires installing the Insiders release (inherent instability), plus a separate plugin for each type of notebook. We would need to develop custom plugins to cover some of our procedures. Custom Notebooks is also heavily reliant on the JavaScript packaging ecosystem, which we are using infrequently these days.

Elixir Livebook requires installing Elixir. We would need to assemble a custom solution for running our automatable tasks.

Jupyter Notebook requires Python and Pip. We would need to assemble a custom solution for running our automatable tasks.

Emacs with org-mode requires installing Emacs.

Minimal friction to adopt

VS Code Custom Notebooks would involve friction around lack of guarantees with stability, the requirement to create custom notebook plugins, and maintaining NPM dependencies.

Elixir Livebook would require learning a new programming language, and creating a custom solution to run our tasks.

Jupyter Notebook would require many team members to learn a new programming language, and we’d need to create a custom solution to run our tasks.

Emacs org-mode would require learning some basic Emacs conventions and maybe a bit of lisp.

Can execute the technologies we use

While any of these options is capable of executing technologies we use, Emacs org-mode is the most capable out of the box. Org-mode is also mature and there is a wide ecosystem of plugins.

Emacs org-mode

Given the current team context, Emacs org-mode seems like a good choice. If we were working more with Python, JavaScript, Elixir, and/or machine learning, one of the other options would rank higher.

Below is an org file that demonstrates a basic runbook implementation with a code block dependency chain.

* Hello World

  This is a hello world notebook.

  To execute any of the code blocks, place the cursor in the block and type CTRL-C CTRL-C.

** Hello World Setup

   The below code block adds shell execution capability to the org babel session (default is emacs-lisp only). This block has been added as a dependency for subsequent code blocks.
   
   #+NAME: setup
   #+BEGIN_SRC emacs-lisp
   (org-babel-do-load-languages
    'org-babel-load-languages
    '((shell . t)))
   #+END_SRC

   #+RESULTS: setup

** Hello World Shell

   The below code block prints the current Unix timestamp.
   
   #+NAME: hello-shell
   #+BEGIN_SRC shell :var preflight=setup
   date +%s
   #+END_SRC

   #+RESULTS: hello-shell
   : 1649002346

** Hello World REST

   The below code block executes a cURL command to convert the current Unix timestamp (from the above code block) to a date-time via a public API (contrived, but useful as a demonstration).

   #+NAME: hello-rest
   #+BEGIN_SRC shell :var shellstamp=hello-shell
     curl "https://showcase.api.linx.twenty57.net/UnixTime/fromunix?timestamp=$shellstamp"
   #+END_SRC

   #+RESULTS: hello-rest
   : 2022-04-03 16:16:45

And here’s a link to the same document as a GitHub Gist (note the results sections are not printed but can be viewed in the raw document):