I’ve been playing around with progress bars in the terminal, and I think I’ve created something genuinely useful.

Yes, I know there are multiple options already available for this, this is mostly just an experiment for me. I wanted to build a Ruby library that could be used for command-line scripting, with CLI executables that made it easy to use when scripting in any language — not just Ruby, with a few options I didn’t see elsewhere.

The result is ruby-progress, a gem that provides four different animated progress indicators, each with its own visual style and use cases.

If you’re scripting in Ruby, I do highly recommend the TTY tools from Piotr Murach, such as tty-progress. Piotr’s TTY tools have Ruby APIs. ruby-progress is designed more for use in other shell scripts than it is for detailed Ruby scripting. This tool owes a lot to Piotr’s work.

The Four Progress Indicators

Ripple
Creates a wave-like effect across text, with the characters rippling through different visual states. It supports rainbow colors, inverse highlighting, and case transformations. Perfect for text-heavy operations where you want something more dynamic than a simple spinner.
Worm
Displays a moving dot pattern that crawls across the screen using Unicode characters. It includes multiple styles (circles, blocks, geometric shapes) and can move in any direction. Great for file operations, network transfers, or any continuous background task.
Twirl
Provides classic spinning indicators with over 35 different spinner styles — from simple dots to complex geometric patterns. It’s the most traditional of the four, but with way more visual variety than typical spinners.
Fill
The only determinate indicator in the bunch — an actual progress bar that shows completion percentage. It can be controlled via command execution or updated programmatically through daemon control messages.

Installation and Quick Start

Installation is straightforward:

gem install ruby-progress

All four indicators are available through a unified prg command:

# Basic usage
prg ripple "Processing files..."
prg worm --message "Loading..." --style blocks
prg twirl --message "Working..." --style dots --speed fast
prg fill --total 100 --report

# With command execution
prg ripple "Building..." --command "make build" --success "Build complete!" --checkmark

You can also use the individual commands directly: ripple, worm, twirl, and fill.

The Killer Feature: Daemon Mode

Here’s where things get interesting. All four indicators support daemon mode, which lets you run a progress indicator in the background while your scripts execute other commands. This is useful for complex workflows.

# Start a background spinner
prg worm --daemon-as deployment --message "Deploying application..."

# Execute your actual deployment steps
git push production main
kubectl apply -f manifests/
./run-migrations.sh

# Stop the spinner with a success message
prg job stop --daemon-name deployment --message "Deployment complete!" --checkmark

The daemon mode uses Process.fork and Process.detach, so there are no shell job notifications cluttering your output. The progress indicator runs cleanly in the background, providing visual feedback without interfering with your script’s execution.

Keeping Output Clean

One of the challenges with daemon mode is preventing command output from disrupting the animation. By default, when you run a progress indicator in daemon mode, any STDOUT or STDERR output from commands executed in your script will appear on the terminal and potentially mess up the animation display.

Ruby-progress handles this intelligently. When running in daemon mode, the animation continues on its dedicated line while your commands execute. However, if you want to see the output from those commands, you have options:

# Run command with animation, show output after completion
prg ripple "Building..." --command "make build" --stdout

# Stream output live while animation runs (reserves terminal rows)
prg worm "Installing..." --command "npm install" --stdout-live --output-lines 5

# Run daemon and manually capture output from your script commands
prg worm --daemon-as build --message "Building..."
make build > /tmp/build.log 2>&1
prg job stop --daemon-name build --message "Build complete!" --checkmark
cat /tmp/build.log

The --stdout-live flag is particularly useful — it reserves a section of the terminal to display live command output while the animation continues above or below it. You control how many lines to reserve with --output-lines and where they appear with --output-position (above or below the animation).

Job Control Commands

The prg job command provides subcommands for controlling background indicators:

  • prg job stop — Stop a running daemon with an optional message
  • prg job status — Check if a daemon is running and show its PID
  • prg job advance — Update a fill progress bar by a specific amount
# Check if a daemon is running
prg job status --daemon-name mytask

# Advance a progress bar remotely
prg fill --daemon-as progress --total 100
prg job advance --daemon-name progress --amount 10

# Stop with error state
prg job stop --daemon-name mytask --message "Build failed!" --error
🔒

Premium Content

Library and advanced usage

Real-World Use Cases

Deployment Scripts: Show continuous progress during multi-step deployments without blocking command output.

Data Processing: Provide visual feedback during long-running data imports or transformations.

Build Systems: Integrate into Rake or Make tasks to show progress during compilation.

CI/CD Pipelines: Add visual indicators to pipeline scripts for better monitoring.

System Administration: Show progress during backups, database dumps, or file synchronization.

Try It Out

The easiest way to get started:

gem install ruby-progress
prg ripple 'Hello, World!'

Or check out the GitHub repository for full documentation, examples, and the complete API reference. The README includes detailed guides for each indicator type and advanced usage patterns.

The gem is also available on RubyGems, and the latest release includes significant improvements to daemon mode handling and job control commands.