Skip to content
gjnailPublic

About

One shell setup for zsh, bash, fish and PowerShell on Windows, macOS and Linux: prompt themes, aliases, tab completion, suggestions and a shared Ctrl+R history. Plus Opal Terminal, opal's own terminal app, which comes with its own bash on Windows like Git Bash.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

opal

CI Terminal Support opal on Ko-fi

opal is a shell setup and a terminal of its own, sharing one config file.

The opal program sets up zsh, bash, fish and PowerShell on Windows, macOS and Linux. Every shell gets the same prompt, aliases, tab completion, suggestions and command history, written in that shell's own syntax.

Opal Terminal is opal's own terminal app. On Windows it comes with its own bash: Opal Bash is MSYS2's bash and Unix tools, set up with opal and kept apart from your other shells. It also has tabs and split panes, inline images, quick select, and a command palette that searches the history every shell writes. It runs on Windows today. The macOS and Linux builds pass their tests in CI but haven't been used on real machines yet.

Website · Getting started · Opal Terminal · Configuration · Plugins · FAQ · Download

The fire, black and boulder themes in zsh, bash, fish and PowerShell

What's in opal

What it does Where
Prompt Three themes, git status, command duration, exit codes, virtualenvs, SSH and root markers all shells
Aliases and plugins Git aliases and other plugins, written once and translated into each shell's syntax all shells
Tab completion Git branches, remotes and changed files; opal's own commands; completions generated by docker, kubectl, gh and other tools all shells
Suggestions Grey text completing what you type from history; Tab or Right arrow accepts it fish, zsh, PowerShell with PSReadLine 2.1+, bash with ble.sh
Shared history One history for every shell, fuzzy-searched with Ctrl+R all shells (bash 4+)
Directory jumping j proj goes to the most used directory matching "proj" all shells
Tools open, clipboard, extract, ports, and pkg install for whichever package manager you have all shells
Opal Terminal A terminal app with tabs, splits, inline images, quick select, a palette over the shared history, session restore Windows; macOS and Linux build but are untested
Opal Bash Opal Terminal's own bash, with ls, grep, sed, awk, find, less, tar and the other Unix tools, separate from your other shells Windows

See Platform support for what has been tested where.

Install

On Windows, in PowerShell:

irm https://raw.githubusercontent.com/gjnail/opal/main/install/install.ps1 | iex

On macOS and Linux (and in WSL):

curl -fsSL https://raw.githubusercontent.com/gjnail/opal/main/install/install.sh | sh

The scripts download the latest release, check it against SHA256SUMS.txt, put opal in %LOCALAPPDATA%\opal\bin or ~/.local/bin, and run opal setup. From a clone of this repository they build it with Go instead (1.22 or newer, 1.24 or newer on macOS).

opal setup finds every shell on the machine and adds a small marked block to each one's startup file: .zshrc, .bashrc, fish's conf.d/opal.fish, and the profiles of Windows PowerShell and PowerShell 7 (including ones OneDrive has moved). It keeps a .opal-backup of each file it changes and imports your existing shell history. On Windows it offers to upgrade PSReadLine when yours is too old for suggestions. Open a new terminal afterwards; opal doctor shows what opal detected and which features are on.

The scripts also install Opal Terminal: on Windows to %LOCALAPPDATA%\opal\terminal with a Start menu shortcut, on macOS to ~/Applications/Opal Terminal.app, and on Linux to ~/.local/bin with a menu entry. On Windows that includes Opal Bash. On Linux they skip it when no graphical session is running, and on WSL and Termux. Set OPAL_NO_TERMINAL=1 (or pass -NoTerminal to install.ps1) to leave it out. From a clone they build it when Go 1.26 is there; otherwise they download it, which works with releases after 0.1.0. If that part fails, opal itself stays installed.

Checking a download

Each release has a SHA256SUMS.txt with the checksum of every archive, and opal update refuses a download that doesn't match it. GitHub also keeps a signed record that each archive was built from this repository by the release workflow. To check one with the GitHub CLI:

gh attestation verify opal_windows_amd64.zip --repo gjnail/opal

Opal Terminal's archives (opal-terminal_windows_amd64.zip and so on) have their own opal-terminal_SHA256SUMS.txt and are attested the same way, by the terminal release workflow.

Updating and removing

opal update installs the latest release, or pulls and rebuilds if you built opal from a clone. It updates the opal program only; running the install script again updates Opal Terminal, including Opal Bash.

To remove it, run opal setup --remove, which takes the marked blocks out of your startup files. Then delete the program and its folders:

  • the program: %LOCALAPPDATA%\opal\bin or ~/.local/bin/opal. On Windows, also remove %LOCALAPPDATA%\opal\bin from your user PATH.
  • the config: ~/.config/opal on every system (%USERPROFILE%\.config\opal on Windows).
  • the data: %LOCALAPPDATA%\opal on Windows, ~/.local/share/opal elsewhere.
  • Opal Terminal: %LOCALAPPDATA%\opal\terminal and the Start menu's Opal Terminal shortcut on Windows, ~/Applications/Opal Terminal.app on macOS, and on Linux ~/.local/bin/opal-terminal, ~/.local/share/applications/opal-terminal.desktop and ~/.local/share/icons/hicolor/256x256/apps/opal-terminal.png.

Prompt and themes

opal theme preview        # all themes, as each shell would show them
opal theme set boulder    # takes effect at the next prompt
  • fire: two lines, a gradient path, git status, and the duration and exit status on the right. The default.
  • black: colored blocks, with the shell's name in the first one. Uses powerline separators if you have a Nerd Font.
  • boulder: one line with a shortened path and compact git status.

Inside a git repository the path starts at the repository's folder. After the branch come commits ahead and behind, then staged, modified and untracked files, stashes, conflicts, and any rebase or merge in progress. The duration appears after commands that take longer than two seconds, and the exit code (with the signal name) after commands that fail. Python virtualenvs, background jobs, and user@host over SSH, in containers or as root or administrator are shown too.

The prompt symbol's color depends on the shell (green in zsh, red in bash, gold in fish, blue in PowerShell), so it's always clear which one you're in. zsh, fish and PowerShell redraw finished prompts as just that symbol, which keeps scrollback short.

Themes are TOML files; copy one from internal/assets/themes into ~/.config/opal/themes/ to make your own. A theme also sets the syntax colors of fish, PSReadLine and zsh-syntax-highlighting, and the colors of Opal Terminal.

More on the website: Themes.

Tab completion

Type git checkout and press Tab to see your branches. The git aliases complete the same way (gco then Tab). zsh, bash and fish already complete git; PowerShell doesn't, so opal adds it there, along with completion for its own commands and aliases in every shell.

If docker, kubectl, gh, helm, uv, deno, pnpm, just or winget is installed, opal also loads the completion script that tool generates. It's cached and loaded the first time you press Tab after that command, so it doesn't slow down starting a shell.

Suggestions

Start typing a command you've run before and grey text shows the rest of it. Tab or the Right arrow accepts it. The suggestions come from fish and PSReadLine themselves, from opal's own engine in zsh (or zsh-autosuggestions if you load it), and from ble.sh in bash when it's installed. In PowerShell, Ctrl+Space opens the completion menu even while a suggestion shows, and F2 switches to a list of suggestions.

Shared history

Every command from every shell goes into one history file. Ctrl+R opens a full-screen search over all of it: type words in any order, pick one with the arrow keys, and Enter puts it on your command line. Pressing Ctrl+R again narrows the list to the current folder, then to the current shell.

Setup imports the history PowerShell, bash, zsh and fish already have. Commands that start with a space aren't recorded, as in bash and zsh, and shared = false under [history] stops recording entirely. The history file is readable only by your account.

Directory jumping

opal remembers the folders you visit. j proj goes to the folder you use most whose path contains "proj", and j work api narrows it further. With fzf installed, ji lets you pick from a list. Opal Terminal's command palette reads the same list.

Plugins

Built in: core, git, jump, python, node, docker, kubectl and pkg. opal plugin list shows which are active in the current shell.

A plugin is a TOML file. Plain strings work in every shell, and tables can differ per shell and per OS:

name = "mine"
description = "My shortcuts"
requires = ["terraform"]            # skipped where terraform isn't installed

[aliases]
tf  = "terraform"
tfp = "terraform plan"
ll  = { unix = "ls -lh", pwsh = "Get-ChildItem" }

[functions.tfw]
sh   = 'terraform workspace select "$1"'      # bash and zsh
fish = 'terraform workspace select $argv[1]'
pwsh = 'terraform workspace select $args[0]'

Aliases become fish abbreviations, and PowerShell functions that pass on arguments and pipeline input. PowerShell's own aliases, such as gc and gl, are left alone unless you say otherwise.

Put a plugin in ~/.config/opal/plugins/, or publish it as a git repository and install it with opal plugin install <user>/<repo>. The plugin guide covers the rest.

Configuration

~/.config/opal/config.toml is read by every shell, on every OS, and by Opal Terminal. opal config edit opens it; the file explains each setting. Your own [aliases], [functions] and [env] go there too and take precedence over plugins. See the configuration reference.

Commands

Command What it does
opal doctor Shows what opal detected (OS, shell, terminal, colors) and which features are active
opal setup Adds opal to every shell's startup file; --remove takes it out
opal update Installs the latest release, or rebuilds from the checkout it was built from
opal terminal Opens Opal Terminal in the current folder; -profile NAME picks the shell
opal theme preview / set Shows every theme in every shell, or switches theme
opal plugin list / install / update Manages plugins
opal history The Ctrl+R picker; opal history list 20, opal history import
opal open <path or url> Opens a file, folder or URL with the default app, including from WSL
opal clip copy / paste Uses the system clipboard, or OSC 52 over SSH
opal extract <archive> Unpacks zip and tar archives (and xz, zst, 7z, rar with the usual tools) into a new folder
opal ports [port] Lists listening TCP ports and the processes behind them
opal pkg install <name> Runs brew, apt, dnf, pacman, zypper, apk, winget, scoop or choco

More on the website: Commands.

Opal Terminal

Opal Terminal is opal's own terminal app, in terminal/. It's written in Go on Gio with its own escape sequence parser and screen model, and on Windows it comes with Opal Bash. It reads the same config.toml as the prompt, takes its colors from the same theme, and uses the command marks the prompt emits, so the two work as one tool. It also runs any other shell or program; the shell integration features need a prompt that emits OSC 133 marks, as opal's does.

It's developed and used on Windows. The macOS and Linux code builds and passes its tests in CI on every change, but nobody has run it on a Mac or a Linux desktop yet.

The website's Opal Terminal page covers the same ground with every default key for Windows, Linux and macOS. The keys below are the Windows and Linux defaults. macOS uses Cmd where they use Ctrl+Shift, and every key can be changed.

Opal Bash

On Windows, Opal Terminal comes with its own bash: MSYS2's bash and runtime, with the Unix tools you'd expect: coreutils (ls, cp, mv, cat, sort, wc and the rest), grep, sed, awk, find and xargs, diff, less, tar, gzip and which. New tabs open it unless shell in config.toml names another shell.

It's kept apart from the rest of the machine:

  • It starts with its own startup file, shell/etc/opal/bashrc in Opal Terminal's folder, instead of ~/.bash_profile and ~/.bashrc. That file loads opal, so the prompt, aliases, completion and Ctrl+R history are there without opal setup editing any startup file. Your own additions go in ~/.config/opal/bashrc.
  • Its up-arrow history is its own, in opal's data folder (%LOCALAPPDATA%\opal\bash_history). Ctrl+R still searches the commands of every shell.
  • Nothing is added to your PATH, and your other shells stay as they were. Inside Opal Bash the bundled tools come first, then your Windows PATH, so git, node, python and other Windows programs work as usual.
  • Drives are /c, /d and so on, /tmp is your Windows temp folder, and ~ is your Windows profile folder (or HOME, if you've set it).

The tools are MSYS2 packages, pinned by version and checksum in packages.lock. MSYS2 builds them for x64 only, so the ARM64 download has the x64 build, which Windows 11 on ARM runs under emulation; that hasn't been tried yet. Their licenses (mostly the GPL) are listed in the shell/PACKAGES.txt file that comes with them, and each release has their source as opal-terminal_shell-sources.tar.

Tabs and panes

  • Tabs can be dragged to reorder, closed with a middle click, renamed, and duplicated.
  • Panes split right, down, or along the longer side, with dividers you can drag or move from the keyboard. A pane can be zoomed to fill the tab.
  • Broadcast mode sends what you type to every pane in the tab.
  • New tabs can run any shell Opal Terminal finds: Opal Bash, PowerShell 7, Windows PowerShell, Command Prompt and each WSL distribution on Windows, and the shells in /etc/shells elsewhere. Your own profiles (an ssh command, a shell with extra arguments, a working directory, environment variables) go in config.toml; they're added to the list, and new tabs open one only if shell names it.

Shell integration

With opal's prompt, the terminal knows where each command starts and ends:

  • a mark in the gutter next to each command, colored by its exit status;
  • Ctrl+Up and Ctrl+Down jump between prompts;
  • Ctrl+Shift+E selects the last command's output, and the palette can copy it;
  • clicking inside the command you're typing moves the shell's cursor there;
  • when a command that ran longer than 10 seconds (configurable) finishes in a background tab or an unfocused window, the tab gets a note and you get a desktop notification. On Windows the taskbar button also flashes, and on macOS the Dock icon bounces.

Since the terminal bundles the Nerd Font symbols, opal's prompt uses Nerd Font icons inside it without any setup.

Command palette, history and directories

Ctrl+Shift+P lists every action with its key, fuzzy-matched as you type. After the actions come the aliases and functions opal defines in the pane's shell, from the enabled plugins and from your config: Enter types one at the prompt, Shift+Enter runs it. An alias is typed as the command it stands for. Start the query with $ to list only those.

Start the query with ! to search opal's shared history from every shell instead: Enter types the command at the prompt, Shift+Enter runs it. Start it with @ to list the directories j knows, most used first, and Enter opens a new tab there. Ctrl+Shift+H and Ctrl+Shift+J open those two lists directly.

Quick select

Ctrl+Shift+Space puts a one- or two-letter label on every URL, path, git hash, IP address, email address and UUID on screen. Typing a label copies that match; typing it in uppercase also pastes it at the prompt. The labels start on the home row.

Find, selection and links

  • Find in scrollback (Ctrl+Shift+F), with case and regex toggles.
  • Select by character, word (double-click), line (triple-click) or block (Alt+drag). Copy on select is optional. Ctrl+C copies when text is selected and interrupts the program when nothing is.
  • Ctrl+click opens links, both OSC 8 hyperlinks and plain URLs in the text.

Inline images

Sixel, the kitty graphics protocol (chunked, compressed and file transfers, placements and deletion) and iTerm2's File= sequence all work. Images belong to the line they start on: they scroll, reflow and leave the scrollback with their text. kitty's Unicode placeholders and animation aren't done yet.

On Windows, the ConPTY built into the system drops the escape sequences images use. The Windows release archives include Microsoft's newer conpty.dll and OpenConsole.exe, and Opal Terminal uses them when they sit next to the program. For a build of your own, terminal/scripts/fetch-conpty.ps1 puts them there.

Text and colors

  • Colors come from the opal theme, so the terminal matches the prompt. Individual colors and the 16-color palette can be overridden, and a minimum contrast setting lifts text that's hard to read on its background.
  • Font fallback covers CJK, color emoji (COLR and PNG) and the Nerd Font icons the prompt uses. The icons are bundled, so nothing needs installing.
  • Box drawing, block elements, braille, sextants and powerline separators are drawn from geometry instead of the font, so they line up without gaps at any size.
  • The emulation follows xterm: scrollback that reflows on resize, true color, curly and colored underlines, grapheme clusters, bracketed paste, focus events, mouse reporting, the kitty keyboard protocol, synchronized output, and progress reports.

Notifications and the clipboard

Programs can post desktop notifications with OSC 9, 99 and 777. They show as toasts on Windows, in Notification Center on macOS, and through the freedesktop notification service on Linux. By default they only appear when the window isn't focused.

Programs may set the clipboard with OSC 52, which is how copying works over ssh. Reading it is off by default, since any program you run, including on a remote machine, could otherwise read what you last copied.

Session restore

When you close the last window, its tabs, splits, shells, working directories and up to 2000 lines of each pane's output are saved, and they come back on the next launch with their command marks. Closing the last tab instead starts fresh next time. restore_session = false turns this off.

Settings

Ctrl+Comma (Cmd+Comma on macOS) opens a settings page for fonts, cursor, colors, shell, scrollback, notifications, the clipboard and every keybinding. Changes apply as you make them. They're written into the [terminal] table of config.toml line by line, so your comments and the rest of the file stay as they were. The terminal README lists every setting and default key.

Building Opal Terminal

The install scripts install it from the release archives, or build it when run from a clone. To build it by hand, it needs Go 1.26 or newer, and cgo on macOS and Linux (see Gio's install notes for the Linux packages).

cd terminal
go build -ldflags=-H=windowsgui -o opal-terminal.exe .   # Windows
go build -o opal-terminal .                               # macOS and Linux

On Windows, run scripts/fetch-conpty.ps1 in the same folder for image support, and go run ./tools/fetchshell for Opal Bash, which downloads its packages from MSYS2 and writes them to the shell folder the program looks for next to itself. opal-terminal -list-profiles shows the shells it found, -profile NAME starts one, and anything after the flags runs instead of a shell (opal-terminal htop).

Platform support

Windows macOS Linux
opal Windows PowerShell 5.1 and bash by hand; those and PowerShell 7 in CI bash 3.2, zsh and PowerShell 7 in CI bash 5, zsh, fish and PowerShell 7 in CI
Opal Terminal Yes Builds and passes tests in CI; not run on a Mac yet Builds and passes tests in CI; not run on a desktop yet
Opal Bash Yes (x64; the x64 build under emulation on ARM64, untested) Not included; the system's shells are used Not included; the system's shells are used
Inline images Yes, with the newer ConPTY Untested Untested
Desktop notifications Yes (toasts) Untested (Notification Center) Untested (freedesktop service or notify-send)

opal is developed on Windows 11 with Windows PowerShell 5.1 and bash. CI runs the test suite on Windows, macOS and Linux and loads opal into each of the shells above on every change. WSL counts as Linux. Reports from other shells, terminals and systems are welcome.

Privacy

opal and Opal Terminal run locally. There are no accounts, no analytics, and nothing is sent anywhere. opal only goes online when you run opal update, opal plugin install or opal plugin update, and on Windows when opal setup offers to upgrade PSReadLine and you accept. Opal Terminal has no network code. Building it from a clone downloads Opal Bash's packages from MSYS2 (repo.msys2.org).

What they store:

  • ~/.config/opal/: config.toml, and your own themes and plugins.
  • %LOCALAPPDATA%\opal on Windows, ~/.local/share/opal elsewhere: history.tsv (the shared history), jump.tsv (remembered folders), caches for git status and tool completions, Opal Bash's bash_history, and Opal Terminal's terminal-session.json, which holds the recent output of each pane for session restore.

How it works

opal

opal is a single program. When a shell starts, opal init <shell> prints code written for that shell, and each prompt calls opal to draw itself, so nothing is emulated.

  • bash 3.2 (macOS), 4.4 and 5.x all work. Command timing uses PS0 and EPOCHREALTIME where they exist and is skipped on 3.2.
  • In PowerShell, the init script is pure ASCII, and the prompt decodes opal's output as UTF-8, so glyphs survive Windows PowerShell's console code page.
  • The prompt text is stored in a variable that the shell never expands again, so a directory named $(rm -rf ~) is displayed, not run.
  • git status gets 200 ms by default. In a repository where it takes longer, the prompt shows the last known counts and updates them in the background.
  • Colors fall back from truecolor to 256 and 16 colors, and glyphs from Nerd Font to plain Unicode to ASCII, depending on the terminal.
  • The prompt emits OSC 133 command marks and OSC 7 working directory reports, which Opal Terminal, and other terminals that understand them, use for shell integration.

Opal Terminal

The shell runs on a pseudo terminal: ConPTY on Windows, a Unix pty on macOS and Linux. Its output goes through Opal Terminal's own parser into a screen model with scrollback, which is separate from the window code and tested on its own.

Each row of the screen is drawn into an image on the CPU, with glyphs from a cache, and the rows are cached by their content, so scrolling only draws the rows that are new. Gio composites the rows on the GPU and draws the cursor, selection and search highlights over them. Drawing the text with Gio's own GPU text paths was tried first and took about 60 ms a frame for a 200 by 60 screen.

On the development machine (AMD Ryzen 7 9800X3D), the parser takes in plain text at about 228 MB/s and colored text with CJK characters at about 118 MB/s, and drawing a 200-column row takes about 31 µs. While a program floods the terminal with output, a frame takes about 1.5 ms to build. To measure on your machine:

cd terminal
go test -run '^$' -bench . ./internal/vt ./internal/render

See the terminal README for the source layout.

Opal Bash

Opal Bash is an MSYS2 root in the shell folder next to opal-terminal.exe: usr/bin holds bash, the tools and msys-2.0.dll, and etc holds the mount table, the account lookup settings and Opal's startup file. Opal Terminal starts it as bash --noprofile --rcfile /etc/opal/bashrc -i.

tools/fetchshell builds it. -update resolves the packages in packages.txt, and everything they depend on, against MSYS2's package database and writes packages.lock. A build then downloads exactly the files in the lock, checks each one's SHA-256 against it, and unpacks them, leaving out manuals, translations, headers, and all but the common terminal descriptions.

Contributing

See CONTRIBUTING.md. Please report security problems, such as a way to make a shell run a command it shouldn't, privately as described in SECURITY.md.

Participation is covered by the Code of Conduct.

Support

opal is free. If it's useful to you and you'd like to say thanks, you can support it at ko-fi.com/gnail.

License

MIT.

Opal Terminal bundles Symbols Nerd Font Mono from the Nerd Fonts project, and a copy of Gio v0.10.3 with a few input fixes; see the terminal README for their licenses. Opal Bash is made of MSYS2 packages under their own licenses, mostly the GPL, as described above.

About

One shell setup for zsh, bash, fish and PowerShell on Windows, macOS and Linux: prompt themes, aliases, tab completion, suggestions and a shared Ctrl+R history. Plus Opal Terminal, opal's own terminal app, which comes with its own bash on Windows like Git Bash.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages