A Bash plugin for modern command line editing.
When Bash prompts you for a command, a library called readline handles your keystrokes. Readline lacks many features users have come to expect. Flyline is a readline replacement that provides an enhanced line editing experience with: - Intellisense style autosuggestions - Change directory using your prompt - Rich prompt customizations, (asynchronous widgets), and animations - Fuzzy history searching - Mouse support (click to move cursor, select text) - Improvements to Bash's tab completion - Synthesize tab completion suggestions with flycomp - Agent assisted command writing - Tooltips - Text selection - Auto close brackets and quotes - Syntax highlighting - Runs in the same process as Bash - Cursor animations and styles
Flyline is similar to ble.sh but is written in Rust and uses ratatui.rs to more easily draw complex user interfaces.
[!IMPORTANT] After installing, run
flyline run-tutorialand if you don't like the mouse capturing:flyline mouse --mode disabled
install.sh[!TIP] Run the following command to download flyline and update your
.bashrcto load the latest version. No need forsudo!
curl -sSfL https://github.com/HalFrgrd/flyline/releases/latest/download/install.sh | sh
On macOS you must first install a version of Bash that supports custom builtins: brew install bash
Arch users can install the AUR package:
paru -S flyline
Download the latest libflyline.so for your system from the releases page. If you are on Linux, you probably want the gnu variant unless you know you are on a musl based Linux distro (e.g. Alpine, Chimera).
Then, in your .bashrc (or in your current Bash session):
enable -f /path/to/libflyline.so flyline
flyline run-tutorial
Clone the repo and run:
cargo build
enable -f /path/to/flyline_checkout/target/debug/libflyline.so flyline
flyline run-tutorial
Installation notes
Disable flyline with enable -d flyline.
Taken from https://www.gnu.org/software/bash/manual/bash.html:
The -f option means to load the new builtin command name from shared object filename, on systems that support dynamic loading. If filename does not contain a slash, Bash will use the value of the BASH_LOADABLES_PATH variable as a colon-separated list of directories in which to search for filename. The default for BASH_LOADABLES_PATH is system-dependent, and may include "." to force a search of the current directory.
Bash 4.4 introduced BASH_LOADABLES_PATH
Bash 5.2-alpha added a default value for BASH_LOADABLES_PATH.
Check your Bash version with: bash --version
So on Bash at least as recent as 5.2, if you install flyline to one of: - /opt/local/lib/bash - /opt/pkg/lib/bash - /usr/lib/bash - /usr/local/lib/bash - /usr/pkg/lib/bash
Then you can simply run enable flyline.
Flyline sets up its own tab completion
so you can type flyline <Tab> in your shell to interactively browse and configure settings. Copy the commands into your .bashrc so they persist.
Explore this README and examples for what you can configure.
Flyline supports dynamic content in PS1, RPS1 / RPROMPT, and PS1_FILL.
The PS1 environment variable sets the left prompt just like normal. See Bash prompt documentation, Arch Linux wiki, or Starship for more information.

PS1='\u@\h:\w$ '
PS1='\u@\h:\w\n$ '
PS1='\e[01;32m\u@\h\e[00m:\e[01;34m\w\e[00m\n$ '
[!TIP] Do git metrics slow down your prompt loading time? See custom widget or example widgets for a solution.
The RPS1 / RPROMPT variable sets the right prompt similarly to Zsh.

RPS1='\t'
RPS1='\t\n<'
RPS1='\e[01;33m\t\n<\e[00m'
PS1_FILL fills the gap between the PS1 and RPS1 lines.

PS1_FILL='-'
PS1_FILL='🯁🯂🯃🮲🮳' # finger pointing to running man
PS1_FILL='🯁🯂🯃🮲🮳 \D{%.3f}'
PS1_FINAL, RPS1_FINAL, and PS1_FILL_FINAL let you configure transient prompts. When a command is submitted, Flyline performs a final redraw using these environment variables instead of their standard counterparts. This keeps your terminal scrollback history clean by replacing complex, multi-line prompts with a minimal version.
PS1_FINAL='Ran at \D{%Y-%m-%d %H:%M:%S}> '
RPS1_FINAL=''
PS1_FILL_FINAL=''
Flyline recognises the standard Bash time escape sequences and re-evaluates them on every prompt draw, so the time shown is always current:
| Sequence | Output |
|---|---|
\t |
24-hour time — HH:MM:SS |
\T |
12-hour time — HH:MM:SS |
\@ |
12-hour time with am/pm |
\A |
24-hour time — HH:MM |
\D{format} |
Custom format (see below) |
These can be placed in any of the supported prompt variables:
# Right prompt showing 24-hour time in green
RPS1='\e[01;32m\t\e[0m'
# Right prompt showing 12-hour am/pm time
RPS1='\e[01;34m\@\e[0m'
\D{format}Use \D{format} with any Chrono format string to display the time exactly how you want it. This is similar to \D{format} in the Bash prompt documentation, but the format string is interpreted by Chrono rather than strftime.
# Show date and time
RPS1='\e[01;32m\D{%Y-%m-%d %H:%M:%S}\e[0m'
# Show only hours and minutes
RPS1='\D{%H:%M}'
Create custom prompt widgets with flyline create-prompt-widget.
Flyline will replace strings in the prompt matching the widget name with the widget's output.
The available widget types are animation, mouse-mode, copy-buffer, custom, and last-command-duration.
Create your own animations with flyline create-prompt-widget animation --name [your animation name here] [FRAMES]....
Flyline will replace strings in the prompt matching the animation name with the animation:
More examples can be found in examples/animations.sh.
The block below is auto-generated from flyline create-prompt-widget animation --help:
Create a custom prompt animation that cycles through frames.
Instances of NAME in prompt strings (PS1, RPS1, PS1_FILL, and their _FINAL counterparts) are replaced
with the current animation frame on every render. Frames may include
ANSI colour sequences written as `\e` (e.g. `\e[33m`).
Examples:
flyline create-prompt-widget animation --name "MY_ANIMATION" --fps 10 ⣾ ⣷ ⣯ ⣟ ⡿ ⢿ ⣻ ⣽
flyline create-prompt-widget animation --name "john" --ping-pong --fps 5 '\e[33m\u' '\e[31m\u' '\e[35m\u' '\e[36m\u'
See https://github.com/HalFrgrd/flyline/blob/master/examples/animations.sh for more details and example usage.
Usage: flyline create-prompt-widget animation [OPTIONS] --name <NAME> [FRAMES]...
Arguments:
[FRAMES]...
One or more animation frames (positional). Use `\e` for the ESC character
Options:
--name <NAME>
Name to embed in prompt strings as the animation placeholder
--fps <FPS>
Playback speed in frames per second (default: 10)
[default: 10]
--ping-pong
Reverse direction at each end instead of wrapping (ping-pong / bounce mode)
-h, --help
Print help (see a summary with '-h')
The block below is auto-generated from flyline create-prompt-widget mouse-mode --help:
Show different text depending on whether mouse capture is enabled.
Instances of NAME in prompt strings (PS1, RPS1, PS1_FILL, and their _FINAL counterparts) are replaced
with ENABLED_TEXT when mouse capture is on, and DISABLED_TEXT when off.
Examples:
flyline create-prompt-widget mouse-mode '🖱️' '🔴'
# Now use FLYLINE_MOUSE_MODE in your prompt:
PS1='\u@\h:\w [FLYLINE_MOUSE_MODE] $ '
flyline create-prompt-widget mouse-mode --name MOUSE_MODE "on " "off"
Usage: flyline create-prompt-widget mouse-mode [OPTIONS] <ENABLED_TEXT> <DISABLED_TEXT>
Arguments:
<ENABLED_TEXT>
Text to display when mouse capture is enabled
<DISABLED_TEXT>
Text to display when mouse capture is disabled
Options:
--name <NAME>
Name to embed in prompt strings as the widget placeholder. Defaults to `FLYLINE_MOUSE_MODE`
[default: FLYLINE_MOUSE_MODE]
-h, --help
Print help (see a summary with '-h')
Render clickable text in your prompt that copies the current command buffer to the clipboard via OSC 52.
flyline create-prompt-widget copy-buffer '[copy]'
# Now use FLYLINE_COPY_BUFFER in your prompt:
RPS1=' FLYLINE_COPY_BUFFER'
The block below is auto-generated from flyline create-prompt-widget custom --help:
Run a shell command and display its output in the prompt.
The output is passed through Bash's decode_prompt_string so Bash prompt
escape sequences (e.g. \u, \w, ANSI colour codes) are fully supported.
Examples:
# Non-blocking (default): runs in the background; shows the previous output
# while the command is running (empty on the first render).
flyline create-prompt-widget custom --name CUSTOM_WIDGET1 --command 'run_slow_git_metrics.sh'
# PS1 usage:
PS1='\u@\h:\w [CUSTOM_WIDGET1] $ '
# Non-blocking with previous output placeholder while the new output is being computed.
flyline create-prompt-widget custom --name CUSTOM_WIDGET1 --command 'run_slow_git_metrics.sh' --placeholder prev
# Blocking: waits for the command to finish before showing the prompt.
flyline create-prompt-widget custom --name CUSTOM_WIDGET2 --command 'run_something.sh' --block
# Blocking with a 500 ms timeout; falls back to placeholder if slower.
flyline create-prompt-widget custom --name CUSTOM_WIDGET3 --command 'run_slow.sh --flag' --block 500 --placeholder prev
Usage: flyline create-prompt-widget custom [OPTIONS] --name <NAME> --command <COMMAND>
Options:
--name <NAME>
Name to embed in prompt strings as the widget placeholder
--command <COMMAND>
Command string to run; include any flags in the same string, e.g. --command './widget.sh --someflag'
--block [<MS>]
Block until the command finishes, optionally with a timeout in milliseconds. With no value, polls indefinitely (i32::MAX ms ≈ 24.8 days). If the timeout expires the command continues running in the background and subsequent renders will pick up its output
--placeholder <PLACEHOLDER>
What to show while the command is running. Either a number (spaces) or 'prev' (use the previous output of the command)
-h, --help
Print help (see a summary with '-h')
$ claude mcp add flyline \
-- python -m otcore.mcp_server <graph>