Post

Software Showcase #1: Recording terminal sessions using asciinema and its derivatives

CLI tools for recording terminal sessions locally (and to the web) as asciicast files (.cast), GIFs, and animated SVGs

I’m a bit of a software hoarder.

I’m always coming across new tools, libraries, and frameworks for automating tasks or creating cool new things, and I always forget to take note of whatever I come across, so this post is the start of (hopefully) many in a series of me doing double-duty to show off all the interesting bits of software I come across1 (from things as small as bash scripts to things as large as full-blown software toolkits like ffmpeg) and make a formal record of all of them for my own notekeeping (because I have starred so many repositories on GitHub and I can hardly remember what a fraction of them are even about).

What the average terminal session looks like for me whenever I’m trying to run some old CLI tool or executable that I haven’t used for a while:

I usually come across these tools whenever I’m browsing GitHub to find some working piece of software or code to resolve some pain point of mine (or to automate tasks because I’m lazy), and seeing as that I’m trying to figure out how to include GIFs of code running in terminals on blog posts recently2, terminal session recorders are a good place to start.

Terminal Session Recorders

Summary

Use asciinema for recording terminal sessions to local .cast files, replaying .cast files in a terminals, & for uploading .cast files to asciinema.org (or your own server).

  • Recordings uploaded to asciinema.org can be embedded as dynamic asciinema recording iframes in HTML webpages (like those you see throughout this post!)
  • On Windows, use PowerSession-rs (a drop-in replacement fork of asciinema)
  • Use agg to convert asciinema recordings (.cast or web URL) to GIFs
  • Use svg-term-cli to convert asciinema recordings (.cast or web URL) to animated SVGs

What are terminal session recorders?

Terminal session recorders, like asciinema 3, are CLI tools that can record (and playback recordings of) standard input/output in terminal sessions. What makes them different from just using screen recording software is that terminal session recorders run inside a terminal (instead of as a window display capture service running as a GUI program) and store the actual raw text from terminal sessions as a stream of events using a custom file format (asciicast for asciinema), which means that:

  1. Recordings take up much less space compared to video files
  2. You can actually copy the raw text being displayed when playing back recordings4 in the terminal or on the web; and
  3. You can actually customize how terminal sessions look during playback by editing the recorded files or just by changing your playback settings (which means you don’t have to re-record sessions for small modifications like changing font styles)

What an asciinema recording embedded on the web looks like. Shown: “Iterative git rebase with vim”. Source: https://asciinema.org/a/9593

Why I care about terminal session recorders

That’s all very promising, but there’s two very specific reasons as to why I’m interested in terminal session recorders (and if you’re a software developer, you might be too):

  1. I want to be able to show snippets of terminal sessions in blog posts on my website without slowing down pages by loading several videos (of which virtually all are expected to range from tens of seconds to a minute or two in length)

  2. I want to be able to easily create GIFs/animated SVGs for READMEs for my projects on GitHub5

Why asciinema is not enough

More on that second point above, converting recordings from asciicast to GIF/SVG is one area where asciinema is lacking (it only supports its proprietary file format), which is where middleware like agg and svg-term-cli come in (and I’ll be talking about both at length later on).

But before we dive into those asciinema-derivatives, let’s take a quick look at what exactly asciinema has to offer (as well as how we can use it to record and playback terminal sessions).

asciinema

Installation

You can install asciinema using PyPI via pip or using your package repository of choice on Linux, macOS, and FreeBSD (you can find the full list of supported OSes at docs.asciinema.org/manual/cli/installation).

1
> pip install asciinema

As you might’ve noticed, Windows is not listed under supported OSes. There’s a good reason for that, and we’ll get to it when we talk about PowerSession-rs.

Usage

Once you’ve got asciinema installed, there are 3 main commands:

CommandDescription
> asciinema recRecord a terminal session to a local asciicast file
> asciinema playPlay a recording (local file or web URL) in the current terminal
> asciinema upload[^theresalsoauth]Upload a recording to asciinema.org or a self-hosted asciinema server

For uploading, there’s also > asciinema auth for connecting asciinema on your local CLI to your asciinema.org account so you can upload recordings to your account (you can also upload anonymously without having to use the auth command, but anonymous uploads that aren’t linked to an account within 7 days of their upload date are automatically deleted).

> asciinema rec [filename]

Start up a recording session using > asciinema rec [filename] and asciinema will launch a new shell6 in your terminal and start recording standard output. In addition, there are a load of different options[^seemore] you can configure for recordings, some of the more useful of which include:

You can also omit [filename] and just run asciinema rec; after ending the recording, you’ll receive a prompt in the terminal to save the recording locally, upload to asciinema.org, or discard (which will also delete the temporary file used to store the recording).

ArgumentDescription
--stdinRecord standard input (standard output is recorded by default)
--appendAppend to an existing recording
-c, --command=<command>Record output for a single command only7 or specific shell (instead of the default using the $SHELL environment variable)
-i, --idle-time-limit=<sec>Limit recorded terminal inactivity to some max <sec> seconds
See the asciinema docs for more options.

> asciinema play <filename/url>

Replay a terminal session recorded using asciinema rec (at a local file or url) in the current terminal using asciinema play. You can pause/resume playback by pressing space, or end playback by pressing CTRL+c. Similar to rec, you also have some options for:

ArgumentDescription
-i, --idle-time-limit=<sec>Limit replayed terminal inactivity to some max <sec> seconds
-s, --speed=<factor>Set playback speed
-l, --loopLoop playback
-m, --pause-on-markersAutomatically pause playback on markers

What the heck are Markers?

  • Markers are like breakpoints or video chapters in YouTube that allow to mark specific timestamps in recordings for navigation; you can configure the asciinema recorder to have a keyboard shortcut for adding markers during recording or edit an existing recording and insert marker lines as specified in the documentation for asciinema markers. On the web, markers are shown in the video timeline (similar to video chapters in YouTube), and can make jumping to points of interest in a terminal session a lot easier.

> asciinema upload <filename>

This command uploads a local recording to whatever URL is specified in the ASCIINEMA_API_URL environment variable (asciinema.org by default (under whatever account has been authenticated via > asciinema auth or anonymously if you haven’t run that yet).

Try jumping to different markers by clicking on the recording timeline below:

asciinema on the web

You can view your and others’ uploaded recordings on asciinema.org (and there are quite a few cool recordings on there, from a demo of a mapping CLI to iterative git rebasing with vim). More importantly, you can embed uploaded recordings as iframes in HTML pages using some inline JavaScript as below:

1
<script src="https://asciinema.org/a/646222.js" id="asciicast-646222" async></script>

The resulting embedded asciinema recording:

While the look and feel of the embedded player defaults to the original uploader’s settings, you can override settings yourself using the following modifications to the inline script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
  src="https://asciinema.org/a/646222.js"
  id="..."
  data-start-at="00:40"
  data-autoplay="true"
  data-loop="true"
  data-speed="2.75"
  data-idle-time-limit="2"
  data-theme="solarized-light"
  data-poster="npt:1:23"  <!-- player preview frame timestamp -->
  data-cols="65"          <!-- terminal width -->
  data-rows="20"          <!-- terminal height -->
  data-preload="true"
  async>
</script>

The resulting embedded asciinema recording with additional configuration & zoomed in (notice how the autocompletion results in ‘ghost’ text in the terminal due to fewer rows/columns set in the replay options than in the original terminal recording):

Where asciinema falls flat

Problem 1: Windows

The asciinema website and GitHub repository do an exceedingly poor job of telling you this from the get-go, but asciinema does not work on Windows!

I actually installed asciinema on my Windows-based laptop via pip with no issues, only to run into errors when trying to record via asciinema rec, and then when I googled the errors I came across the GitHub issues mentioning that the program isn’t even designed to run on Windows (which is a bit of a bummer).

Thankfully, a port of asciinema for Windows exists in the form of PowerSession-rs, and it has the most8 of the same commands so it can be used as a drop-in replacement for asciinema on Windows (which is an absolute blessing for people chained to Windows like myself).

One slight however: it only supports PowerShell.

Problem 2: GitHub

GitHub READMEs don’t render <script> tags, which means that while you can technically include an image9 that links to a recording on asciinema.org like the below, it will only play the recording after navigating to an external page, which means you can’t get a cool README where there’s an autoplaying video of the code like at github.com/tqdm/tqdm.

GitHub does, however, allow for embedding GIFs and animated SVGs, which is where agg comes in.


agg

agg is a CLI tool (and a successor to the now-deprecated asciicast2gif) for generating GIF files from asciinema recordings[^thefileformat], written by the same developer as asciinema. It’s built using Rust, so you will need to have Cargo installed to be able install it (Cargo is distributed by default with Rust). Files are stored using the asiicast-v2 file format

A GIF generated from an `asciinema` recording using `agg` A GIF generated from an asciinema recording using agg

Usage

> agg <asciicast_filename/url> <output_gif_filename>

You can use agg for rendering GIFs from a local asciicast .cast recording or from URL like the below:

1
> agg input.cast output.gif
1
> agg https://asciinema.org/a/569727 output.gif

There are also a large number of additional options available to customize the look of the generated GIF[^seethewholelistat], including setting:

ArgumentDescription
--font-family <FONT_FAMILY>Specify font family [default: “JetBrains Mono, Fira Code, SF Mono, Menlo, Consolas, DejaVu Sans Mono, Liberation Mono”]
--font-size <FONT_SIZE>Specify font size (in pixels) [default: 14]
--idle-time-limit <IDLE_TIME_LIMIT>Limit idle time to max number of seconds [default: 5]
--line-height <LINE_HEIGHT>Specify line height [default: 1.4]
--speed <SPEED>Adjust playback speed [default: 1]
--theme <THEME>Select color theme [possible values: asciinema, dracula, monokai, solarized-dark, solarized-light, custom]
See the full list of options at github.com/asciinema/agg#usage

Where agg falls flat

The trouble with agg however is that the GIF encoder10 it uses generates very high quality files at the cost of also very high file sizes (which is fine for a handful of GIFs on a GitHub README but can potentially be a strain on resources if displayed on, say, a webpage).

To remedy that, we can use svg-term-cli, which is designed for rendering asiicast recordings to animated SVGs.


svg-term-cli

Why use animated SVGs over GIFs?

For one, animated SVGs are able to look a lot more crisp at larger resolutions than GIFs by using vector images instead of pixel based animation. Adding on to that (and why you should be using animated SVGs instead of GIFs when embedding recordings on websites), this also allows animated SVGs to have a much smaller file size, which is a very nice combination of features, making svg-term-cli almost[^wewillgettothis] the ideal tool for rendering your asciinema recordings (notable exception: you can’t rewind or copy text from recordings, making this more of a cosmetic option.).

To find out why it’s almost ideal (instead of just being ideal), continue reading to the “Where svg-term-cli falls flat” section.

An animated SVG generated from an `asciinema` recording using `svg-term-cli`. An animated SVG generated from an asciinema recording using svg-term-cli.

Usage

After installing svg-term-cli via > npm install -g svg-term-cli(yes, this is in fact a Node.js application), you can render a local asciicast file or a recording at a URL to an animated SVG using the following:

1
> svg-term --cast <filename/url> --out [filename]

> svg-term

svg-term-cli, too, has optional arguments for customizing the rendered SVG’s appearance; some standout options that aren’t present in either of the previous tools include:

ArgumentDescription
--no-cursor [boolean]Disabling cursor rendering
--padding [number]Setting distance between text and image bounds
--window [boolean]Rendering with MacOS window decorations

Where svg-term-cli falls flat

Unfortunately, at the time you’re reading this it’s been 59 months and counting since the last commit (and 77 months since the last commit that actually made any changes to the code) on the svg-term-cli project, so while it still works at the time of writing, we’re probably not going to be able to expect any of the 25 open issues to be closed anytime soon (at least not until someone forks the repo and resumes maintainance for the project).

If you’re looking for a more up-to-date alternative, then there’s the Go-based termsvg, which is a functional but still early-stage CLI tool that’s able to record terminal sessions (just like asciinema) and export them to SVG11.

Unlike PowerSession-rs however, termsvg does not support uploading recordings to asciinema.org

An animated SVG generated from an `asciinema` recording using `termsvg`. Looks just as good (if not better) than one generated by `svg-term-cli`. An animated SVG generated from an asciinema recording using termsvg. Looks just as good (if not better) than one generated by svg-term-cli.




What to explore next

While I’ve covered the most important tools in the terminal session recording realm in this post, there’s still a fair few number of programs out there that record and store recordings in lots of different ways.

The most notable feature that I’ve relegated to a future post is the concept of programmatic terminal session recording generation (that is, writing code to programmatically create recordings of terminal sessions) via tools like vhs which have oodles of options for fine-tuning exactly how you want recordings to look.

But that’s a software showcase for another day.




Footnotes

  1. Including how to set things up and use them, which is something that I have to learn from scratch every time I go to set up my software workflows on yet another device and so it’s something that I want to make note (and while I’m doing that, I might as well share it with everybody else) ↩︎

  2. I’m trying to take blogging seriously right now (for the record, I’ve tried at least twice before and failed to stick with it), and for me that means going all out in making my blog posts multimodal and interesting (which is why I care about these terminal recordings). ↩︎

  3. Despite being constantly reminded my eyes that it’s spelled “as-ciinema”, I just can’t pronouncing it in my head as “ascii-cinema” 😅 ↩︎

  4. Which can be incredibly useful for, say, replicating the actions in a GIF you found for a project or tool online (especially if they have interactivity like Vim or Micro↩︎

  5. one project that I’d really like to spruce up is eagerDB, which I currently just have a rather boring single image for in its README. ↩︎

  6. Q: *What’s the difference between a Terminal and a Shell? A: a shell is a command-line interpreter that processes commands, whereas a terminal is a program (or even a hardware device) that provides a user interface for running a shell. ↩︎

  7. Instead of an interactive shell where you can type in any number of commands and the recording only stops once you enter exit or press CTRL+d ↩︎

  8. At the time of writing PowerSession-rs does not yet support (playing recordings from a URL)[https://github.com/Watfaq/PowerSession-rs/issues/22] or the idle time limit option from asciinema play, among other small features. ↩︎

  9. You can get an SVG of the default preview frame for the asciinema recording by appending .svg to the recording’s URL (e.g. https://asciinema.org/a/bJMOlPe5F4mFLY0Rl6fiJSOp3.svg for https://asciinema.org/a/bJMOlPe5F4mFLY0Rl6fiJSOp3↩︎

  10. github.com/ImageOptim/gifski ↩︎

  11. Might be worth doing a comparison of SVG generations (wrt file size, speed, etc.) between termsvg and svg-term-cli for a future blog post. ↩︎

This post is licensed under CC BY 4.0 by the author.