Skip to content

Overview

What is Moulti?

Moulti changes the way your shell scripts (bash, zsh, etc.) display their output in your terminal. Moulti enables you to assign the numerous lines emitted by your scripts to "steps", i.e. visual, collapsible blocks featuring their own title and color.

Here is what upgrading a Debian system looks like with Moulti:

Interested? Run this demo in a container using docker or podman

Not convinced yet? What if the output of your Ansible playbooks looked like this?

                                        ansible-playbook -C -D -v setup-base-system.yaml                                         ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔                                                   PLAY: Set up base system                                                   ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▶ TASK: Gathering Facts ▶ TASK: timezone : set desired timezone ▶ TASK: apt : include_tasks ▶ TASK: apt : configure apt ▶ TASK: apt : configure Debian sources ▶ TASK: apt : include_tasks ▶ TASK: apt : configure apt ▶ TASK: apt : configure Debian sources ▶ TASK: apt : remove sources.list ▶ TASK: apt : apt update ▶ TASK: hostname : set hostname ▶ TASK: hostname : set FQDN ▶ TASK: motd : set motd ▶ TASK: sshd : ensure openssh-server is installed ▶ TASK: sshd : configure openssh-server ▶ TASK: ssh : ensure openssh-client is installed ▶ TASK: ssh : configure openssh-client ▶ TASK: tools : install base tools ▶ TASK: tools : install client tools ▶ TASK: tools : install file tools ▶ TASK: tools : install locale tools ▶ TASK: tools : install network tools ▶ TASK: tools : install system tools▂▂ ▶ TASK: tools : install terminal tools ▼ PLAY RECAP atwood                     : ok=50   changed=0    unreachable=0    failed=0    skipped=12    rescued=0    ignored=0    bates                      : ok=36  changed=11   unreachable=0    failed=0     skipped=3     rescued=0    ignored=0     l  Lock scroll  s  Save  z  Console   x   Expand all  o  Collapse all  d  Light  h   Help   q  Quit 

Moulti is a tool meant for people who write and execute shell scripts and/or Ansible playbooks. Specifically, if you find yourself scrolling up your terminal to ensure everything went fine while your script is still running, then Moulti is made for you.

By the way, Moulti can also display man pages and unified diff files (with colors courtesy of delta):

                                              man bash                                               ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ BASH(1)                            General Commands Manual                           BASH(1) ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▼ NAME     bash - GNU Bourne-Again SHell ▼ SYNOPSIS bash [options] [command_string | file] ▼ COPYRIGHT     Bash is Copyright (C) 1989-2022 by the Free Software Foundation, Inc. ▼ DESCRIPTION Bash  is  an  sh-compatible  command language interpreter that executes commands read     from the standard input or from a file.  Bash also incorporates useful features  from     the Korn and C shells (ksh  and  csh). Bash is intended to be a conformant implementation of the Shell and Utilities portion▃▃     of the IEEE POSIX specification (IEEE Standard 1003.1).  Bash can be configured to be     POSIX-conformant by default. ▶ OPTIONS ▶ ARGUMENTS ▶ INVOCATION ▶ DEFINITIONS ▶ RESERVED WORDS ▶ SHELL GRAMMAR ▶ COMMENTS ▶ QUOTING ▶ PARAMETERS ▶ EXPANSION ▶ REDIRECTION  l  Lock scroll  s  Save  z  Console   x   Expand all  o  Collapse all  d  Light  h   Help   q  Quit 

                         git show 3ec3b2fba526ead2fa3f3d7c91924f39a0733749                           ▼ Header commit 3ec3b2fba526ead2fa3f3d7c91924f39a0733749 Author:     David Woodhouse <dwmw2@shinybook.infradead.org> AuthorDate: 2005-05-17 12:08:48 +0100 Commit:     David Woodhouse <dwmw2@shinybook.infradead.org> CommitDate: 2005-05-17 12:08:48 +0100     AUDIT: Capture sys_socketcall arguments and sockaddrs     Signed-off-by: David Woodhouse <dwmw2@infradead.org> ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔                                      include/linux/audit.h                                       ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▼  @@ 69,8 69,9 @@+2-1 #defineAUDIT_FS_WATCH        1301    /* Filesystem watch event */ #defineAUDIT_PATH        1302    /* Filname path information */ #defineAUDIT_IPC        1303    /* IPC record */ -#define AUDIT_SOCKET        1304    /* Socket record */ +#defineAUDIT_SOCKETCALL    1304    /* sys_socketcall arguments */ #defineAUDIT_CONFIG_CHANGE    1305    /* Audit system configuration change */ +#defineAUDIT_SOCKADDR        1306    /* sockaddr copied as syscall arg */ #defineAUDIT_AVC        1400    /* SE Linux avc denial or grant */ #defineAUDIT_SELINUX_ERR    1401    /* Internal SE Linux Errors */ ▼  @@ 235,6 236,8 @@+2-0extern int audit_get_stamp(struct audit_context *ctx, externintaudit_set_loginuid(struct task_struct * task uid_tloginuid); externuid_taudit_get_loginuid(struct audit_context * ctx ); externintaudit_ipc_perms(unsignedlongqbytes uid_tuidgid_tgidmode_t mode ); +externintaudit_socketcall(intnargs unsignedlong*args);▆▆ +externintaudit_sockaddr(intlen void*addr); externvoidaudit_signal_info(intsig struct  task_struct *t);  l  Lock scroll  s  Save  z  Console   x   Expand all  o  Collapse all  d  Light  h   Help   q  Quit 

Installation

TL;DR: pipx install moulti; pipx ensurepath

More details in Installation.

How?

Synopsis:

  1. Start a Moulti instance: moulti init
  2. Add a step: moulti step add step_name --title='some clever title here'
  3. Fill it: whatever_your_script_does | moulti pass step_name
  4. Repeat #2 and #3 until your script is done.

Learn how to leverage Moulti by taking your first steps.

Features

As shown in the demo, Moulti enables user interactions through questions:

▼ My first question with Moulti What is your name? ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ Please enter your name in this input field ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ We want information... information... information!

▼ My second question with Moulti What is your name? ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ AliceBobCraigMalloryOscar ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ What a mess: https://en.wikipedia.org/wiki/Alice_and_Bob

▼ My third question with Moulti What is your name? ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ Luka ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ AliceBobNeither, use input ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ I live on the second floor

Moulti also features:

When it comes to look and feel, Moulti can be customised:

Implementation

Moulti is written in Python and leverages Textual, along with Pyperclip, argcomplete and unidiff.

Why Moulti?

For decades, scripts and command-line tools have resorted to various techniques to make it possible to navigate copious output. One of these techniques is to "draw" separators using ASCII characters.

Example

$ my-huge-batch.sh
======== PART 1 ========
[10,000 lines of output]
======== PART 2 ========
[10,000 lines of output]
======== PART 3 ========
[10,000 lines of output]
Huge batch finished, exiting with return code 0.

Implementing such separators is straightforward, and they make it easier to spot and navigate to relevant points of the output, but as mere non-interactive markers, they remain a limited tool. TUIs (Text User Interfaces) offer much more potential, starting with the ability to fold/collapse entire sections, yet remain costly to implement compared with CLI tools. As a CLI-driven TUI, Moulti intends to bridge that gap by bringing specialized TUI capabilities to authors of CLI tools.

Inspiration

Moulti remained a mere idea for a significant time (possibly years).

The idea of driving TUI elements from scripts obviously comes from tools like dialog and whiptail.

At some point, the author stumbled upon multiplex, which is probably the closest thing to Moulti. multiplex was deemed unsatisfying on multiple points (including architecture) and that prompted the development of Moulti.

procmux is also similar to Moulti but did not affect its development.

Acknowledgments

The Textual framework helped a lot, so kudos to the Textual team, and specifically to: