CLI tool
fuelen/owl avatar
fuelen/owl

Owl: an Elixir toolkit for making command line output worth looking at

A toolkit for writing command-line user interfaces.

535 stars15 forksElixirApache-2.0

At a glance

What is it?
Owl is a set of building blocks for terminal interfaces in Elixir, from colourised text and validated input prompts to tables, progress bars and live updating blocks. Its key decision is where it stops: it is for enhancing ordinary scripts, not for building a full screen application.
Who is it for?
Adopt Owl if you write Elixir command line tools and want colour, prompts with validation, tables and progress reporting without hand rolling terminal escape sequences, and you are happy to keep your program running top to bottom. Do not adopt it for a full screen interface, because the README points at TermUI, Ratatouille and ExNcurses for that, and it is explicit that full screen TUI work is harder than it looks.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 141 days ago.
What is it written in?
Mainly Elixir, according to GitHub's language statistics.

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

Editorial analysis

What the library actually provides

Owl is a toolkit for writing command-line user interfaces in Elixir, and the list of what it gives you is long enough to be worth reading in full.

For output, there is colorizing text using tags, printing palette colors, rendering hyperlinks through OSC 8 in supported terminals, and true-color 24-bit ANSI sequences. There is word wrapping and truncation utilities for colorized multi-line text, and there is wrapping multi-line colorized data into ASCII boxes.

For input, there are input controls with validation and casting to various data types, and select and multi-select controls inspired by AUR package managers. There is also editing text in the ELIXIR_EDITOR.

Then the parts that make a tool feel finished. There are tables, progress bars and spinners with support for multiple bars or spinners simultaneously, live updating of multi-line blocks, and capturing:stdio output and printing it above LiveScreen blocks. There is working with a virtual device that partially implements the Erlang I/O Protocol and does not conflict with live blocks, running shell commands and daemons with secure logging and masked secrets,

The theme of the last two is what makes Owl different from a colour library. A CLI tool that runs a long task and prints a log needs to interleave log output with a live progress display, and doing that means intercepting:stdio and reordering it, which is what the virtual device and the LiveScreen blocks are for.

The project is Apache-2.0 licensed, the primary language is Elixir, the default branch is main, and the last push was on 2026-06-04. The release history is v0.13.1 from 2026-06-04, v0.13.0 from 2025-08-29 and v0.12.2 from 2025-02-09, and the package is published on Hex as owl.

The When to use section tells you where the boundary is

The README has a section called When to use Owl, and it is the most useful paragraph in the documentation because it tells you what the library is not for.

If you need a full-screen terminal application, think lazygit or htop, the README points you at TermUI, Ratatouille or ExNcurses. And it warns that full-screen TUI development is often harder than it looks, with no DevTools, no visual inspector and limited layout primitives, so for complex interfaces a Phoenix LiveView might actually be easier to build and maintain.

That is an unusual thing for a library README to say, and it is worth respecting. A full-screen application needs a layout engine, a redraw loop and a screen buffer, and Owl is not that. Phoenix LiveView being the suggested alternative is also a surprise worth noting, since it is a browser-based approach rather than a terminal one, but the argument is about who maintains the interface, not about the medium.

Owl serves a different niche, and the README describes it in one sentence. It enhances regular scripts and CLI tools with just enough interactivity, meaning coloured output, progress bars, input prompts, tables and select menus. Your program still runs top-to-bottom, prints to stdout, and exits. Owl just makes that output more informative and user-friendly.

That is a well-drawn line, and it is the line to keep in mind when you evaluate whether the dependency is worth adding. A script that prints a table and asks a question is what Owl is for; an application with a persistent screen is not.

The virtual device and LiveScreen are the interesting part

Most of the list is standard terminal toolkit work, and two entries are where the design work went.

The first is working with a virtual device that partially implements the Erlang I/O Protocol and does not conflict with live blocks. The second is capturing :stdio output and printing it above LiveScreen blocks.

Put together, those two describe the mechanism for the problem that makes progress reporting in a CLI hard. A program that prints log lines while a progress bar is on screen has two writers of output competing for the same terminal. The usual answer is to have the application route its own logging through the progress bar, which means changing every log call. The other answer is what Owl does: intercept the :stdio output, capture it, and re-render it above the live region, so the application does not have to know about the display at all.

That is a design decision with a cost, and the README is honest about it. A virtual device that partially implements the Erlang I/O Protocol is not a complete implementation, and code that writes to :io directly rather than through :stdio can end up in the wrong place. The alternative, where the application knows about the display, is more code in the application and less magic in the library. Owl has chosen the magic.

The live updating of multi-line blocks is the same idea applied to a region rather than a line, so a panel showing a live table or a running summary can be redrawn in place while the rest of the output scrolls above it.

Installation, and the optional dependency for multibyte characters

The package is installed by adding it to your dependency list in mix.exs:

elixir
def deps do
  [
    {:owl, "~> 0.13"},
    # ucwidth is an optional dependency, uncomment it for multibyte characters support (emoji, etc)
    # {:ucwidth, "~> 0.2"}
  ]
end

The commented line is worth reading rather than skipping. ucwidth is an optional dependency, and uncommenting it is what gives you multibyte character support, for emoji and similar. The word wrapping and truncation utilities need to know how wide a character is, and a character like an emoji occupies more than one column, so without the dependency the width calculations are wrong for anything outside plain ASCII.

That is a small dependency with a real effect on output alignment, and it is the kind of thing you only notice when a table of emoji-carrying names comes out misaligned.

The documentation is on HexDocs at hexdocs.pm/owl, and there is a demo recorded with asciinema in the README, with the code in the examples directory of the repository.

The examples directory is worth browsing for the shape of the API, and the file names describe what each one exercises. There is a walking_owl example and a bar example for progress bars, multiple_bars and multiple_spinners, a multiline_spinner, a resizable_table, a set of owls, an emulate_compilation example, and six_owls.

The project also has the usual Elixir tooling in the repository root: a mix.exs and mix.lock, a .formatter.exs, an examples/ directory, a lib/ directory with the implementation, a test/ directory, an images/ directory for the documentation, a coveralls.json for coverage reporting, and a CI workflow.

A few capabilities worth singling out

Three entries in the list are unusual enough that they deserve a note, because they are the ones you would not expect from a terminal library.

Running shell commands and daemons with secure logging and masked secrets is the one that matters most in practice. Any CLI that shells out to something has to decide what to do with the child's output and what to do about credentials that appear in a command line. A toolkit that handles the second of those, by masking secrets in the log, is removing a class of bug that is easy to introduce and hard to spot.

Rendering hyperlinks through OSC 8 is the second. Terminals that support OSC 8 can make a printed URL clickable, and the way to do that is to emit an escape sequence around the link text. Doing it by hand in every print call is tedious, and a helper that does it correctly is worth having.

The third is the combination of true-color 24-bit ANSI sequences with a palette printer. The palette printer suggests the library can generate a colour table for you, which is what you want when you have a set of semantic colours rather than a fixed scheme, and the true-color support means those colours do not have to be approximated with the 256-colour cube.

The select and multi-select controls inspired by AUR package managers are the other feature with a clear precedent, and the inspiration is deliberate. AUR-style selection is a familiar interaction to anyone who has installed packages on Arch, and a list with a cursor, a filter field and a set of checkboxes is exactly what the multi-select control provides.

And the editing of text in the ELIXIR_EDITOR is a small touch with a real audience, since it lets a prompt ask for a multi-line value using the editor the user already has configured, rather than embedding a line editor that behaves differently from the rest of their shell.

Editorial conclusion

Adopt Owl if you write Elixir command line tools and want colour, prompts with validation, tables and progress reporting without hand rolling terminal escape sequences, and you are happy to keep your program running top to bottom. Do not adopt it for a full screen interface, because the README points at TermUI, Ratatouille and ExNcurses for that, and it is explicit that full screen TUI work is harder than it looks. Before you add it, decide whether your tool needs a live region at all, since the virtual device and LiveScreen machinery is the heavy part of the library, and note that multibyte character support needs the optional ucwidth dependency.

Frequently asked questions

What is Owl in Elixir?

Owl is a toolkit for writing command-line user interfaces in Elixir. It provides colorizing text using tags, input controls with validation and casting to data types, select and multi-select controls, tables, progress bars and spinners, live updating of multi-line blocks, and word wrapping for colorized text.

When should I not use Owl?

The README says that if you need a full-screen terminal application, like lazygit or htop, you should look at TermUI, Ratatouille or ExNcurses, and it notes that full-screen TUI development is often harder than it looks, with no DevTools and limited layout primitives. Owl is for enhancing ordinary scripts and CLI tools with a bit of interactivity.

How do I install Owl in an Elixir project?

Add it to your list of dependencies in mix.exs with `{:owl, "~> 0.13"}`. There is an optional dependency for multibyte character support, ucwidth, which you uncomment if you need emoji and similar characters to be measured and aligned correctly.

How does Owl handle log output while a progress bar is on screen?

It works with a virtual device that partially implements the Erlang I/O Protocol and does not conflict with live blocks, and it captures :stdio output and prints it above LiveScreen blocks. The application still runs top to bottom and prints to stdout; the library re-renders the captured output above the live region.

Official sources

  1. fuelen/owl on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Add this badge to your README

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

Add this badge to your README

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

Was this useful?