SkillAgentSearch skills...

Reef

Paste bash into fish. It just works.

Install / Use

/learn @ZStud/Reef
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

reef

Bash compatibility for fish shell. Just works.

Reef makes bash syntax work seamlessly inside fish. No prefix commands, no mode switching, no learning curve. You type bash — fish runs it.

> export PATH="/opt/bin:$PATH"                          # just works
> for f in *.log; do wc -l "$f"; done                   # just works
> source ~/.nvm/nvm.sh && nvm use 18                     # just works
> echo "Hello $(whoami), it's $((2+2)) o'clock"         # just works

Fish is the fastest, friendliest shell out there. The only reason people don't switch is bash compatibility. Reef fixes that.


Why

Fish has better autosuggestions, syntax highlighting, completions, and startup time than bash or zsh — all out of the box, zero configuration. But paste a command from Stack Overflow and it breaks. export, $(), for/do/done, [[ ]] — none of it works in fish natively.

Every other solution requires you to change your behavior:

  • bass — prefix every command with bass
  • zsh — spend an hour configuring plugins to match fish's defaults
  • just learn fish syntax — the fish community's advice for 20 years

Reef requires nothing. You install it and forget it exists.


Install

Arch / CachyOS (AUR)

yay -S reef              # bash compatibility layer
yay -S reef-tools        # modern tool wrappers (grep->rg, find->fd, cat->bat, cd->zoxide, etc.)

The two packages are independent — install either or both. reef-tools installs the wrappers only — the modern tools themselves are optional dependencies. Install whichever ones you want:

yay -S ripgrep fd sd dust procs eza bat zoxide   # all of them
yay -S bat zoxide                                 # or just the ones you want

Wrappers for tools you haven't installed simply pass through to the original command.

Homebrew (macOS / Linux)

brew tap ZStud/reef
brew install reef

homebrew-core requires 225+ stars (or 90+ forks/watchers) for new formulae — once reef hits that, brew install reef will work without tapping.

Fedora / RHEL (Copr)

sudo dnf copr enable zstud/reef
sudo dnf install reef                # bash compatibility layer
sudo dnf install reef-tools          # optional: modern tool wrappers

Nix

nix profile install github:ZStud/reef
nix profile install github:ZStud/reef#reef-tools   # optional tool wrappers

Or as a flake input:

{ inputs.reef.url = "github:ZStud/reef"; }

Also available via nixpkgs (v0.3.0 update pending):

nix-env -iA nixpkgs.reef

Cargo (crates.io)

cargo install reef-shell

From source

git clone https://github.com/ZStud/reef
cd reef
cargo build --release
fish fish/install.fish              # core only
fish fish/install.fish --tools      # also install tool wrappers

The install script places the binary and fish functions in the right locations. No configuration needed.

Why no Debian/Ubuntu package? Reef uses Rust edition 2024, which requires Rust 1.85+. Ubuntu ships Rust 1.82 (as of Plucky 25.04), so a native PPA build isn't possible yet. Debian/Ubuntu users can install via Homebrew, Nix, cargo install reef-shell, or from source.

Uninstall

AUR:

yay -R reef reef-tools

Homebrew:

brew uninstall reef && brew untap ZStud/reef

Fedora / RHEL:

sudo dnf remove reef reef-tools
sudo dnf copr remove zstud/reef

Nix:

nix profile remove reef

Cargo:

cargo uninstall reef-shell

From source:

fish fish/install.fish --uninstall

How It Works

Reef uses three tiers, each faster than the last:

Tier 1 — Keyword Wrappers (<0.1ms) Fish functions that handle common bash builtins natively.

export VAR=val     ->  set -gx VAR val
unset VAR          ->  set -e VAR
source script.sh   ->  bash sourcing with env capture

Tier 2 — AST Translation (~0.4ms) A custom zero-copy Rust parser converts bash syntax to fish equivalents before execution. Zero dependencies, zero allocations.

for i in $(seq 5); do echo $i; done  ->  for i in (seq 5); echo $i; end
if [[ -n "$HOME" ]]; then echo y; fi ->  if test -n "$HOME"; echo y; end
echo $((2 + 2))                      ->  echo (math "2 + 2")
${var:-default}                      ->  (set -q var; and echo $var; or echo "default")

Tier 2.5 — Confirm Mode (optional) Preview what reef will do before it executes. Shows the fish translation (T2) or indicates bash passthrough (T3), then waits for [Y/n] confirmation.

> export FOO=bar
  -> fish: set -gx FOO bar
  Execute? [Y/n] y                    # Y or Enter = execute, n = cancel

Tier 3 — Bash Passthrough (~1.6ms) Anything too complex to translate runs through bash directly. Environment changes are captured and applied back to your fish session.

declare -A map=([k]=v)               ->  runs in bash, output streamed

Every tier falls back to the next. Nothing breaks — the worst case is 1.6ms of latency, which is faster than zsh's startup time.


Commands

reef on                    # enable reef (default)
reef off                   # disable — raw fish, no translation
reef status                # show current settings
reef display bash          # show commands as you typed them (default)
reef display fish          # show the fish translation on the commandline
reef history bash          # log your original bash input to history (default)
reef history fish          # log translated fish commands to history
reef history both          # log both
reef confirm on            # preview translations before executing
reef confirm off           # execute immediately (default)
reef persist off           # fresh bash each command (default)
reef persist state         # exported vars persist across commands
reef persist full          # persistent bash coprocess — everything persists

Confirm Mode

When enabled (reef confirm on), reef shows what it will do before executing. You get a [Y/n] prompt for every bash command — translations, passthroughs, daemon routes, and source commands.

> export FOO=bar
  -> fish: set -gx FOO bar
  Execute? [Y/n]                      # Enter or y = execute

> some_unsupported_bash
  -> bash passthrough (no fish equivalent)
  Execute? [Y/n] n                    # n = cancel, command stays for editing

This is off by default — zero overhead when disabled. Useful for learning what reef does, debugging translations, or when you want explicit control over what runs.


Persistence Modes

By default, each bash passthrough command runs in a fresh bash subprocess. Variables, functions, and fds set in one command are gone by the next. Reef v0.3 adds two opt-in persistence modes that let bash state survive across commands.

reef persist off (default)

Current behavior. T1 -> T2 -> T3 pipeline. Each T3 passthrough spawns fresh bash.

reef persist state

After each bash passthrough, reef saves the exported environment to a state file. The next passthrough restores it before running your command. Exported variables persist across commands. T2 translation still handles what it can.

> export MY_VAR=hello        # saved to state file
> echo $MY_VAR               # works — env diff synced it to fish
> bash -c 'echo $MY_VAR'     # works — state file restored it in bash

Overhead: ~0.4ms to source a typical state file (30 vars). Persists: exported variables. Doesn't persist: unexported vars, fds, traps, functions.

reef persist full

Spawns a long-lived bash process per fish session. All bash-detected commands route through this single process — T2 translation is skipped to keep bash state consistent. Since it's the same process, everything persists.

> MY_VAR=hello               # unexported — would normally be lost
> echo $MY_VAR               # works — same bash process
> myfunc() { echo "works"; } # function persists
> myfunc                     # works
> exec 3>&1                  # fd persists
> echo "hello" >&3           # works — same process

Overhead: ~1.6ms per command, ~2-4MB for the bash process. Persists: everything — exported and unexported vars, functions, aliases, traps, fds, cwd.

The daemon is cleaned up automatically when your fish session exits.


What's Covered

498 tests covering bash constructs across all tiers.

| Category | Examples | Tier | |---|---|---| | Variables & export | export, unset, declare, local, readonly | 1 | | Command substitution | $(cmd), `cmd`, nested | 2 | | Conditionals | if/then/elif/else/fi, [[ ]], [ ], test | 2 | | Loops | for/do/done, while, until, C-style for ((i=0;...)) | 2 | | Arithmetic | $(( )), (( )), bitwise ops, ternary, pre/post inc/dec | 2 | | Parameter expansion | ${:-}, ${%%}, ${//}, ${#}, ${^^}, ${,,}, ${:offset:len}, ${!ref}, ${@Q} | 2 | | String replacement | ${var/pat/rep}, ${var//pat/rep}, prefix/suffix anchored | 2 | | Case statements | case/esac with patterns, wildcards, char classes | 2 | | Functions | name() {}, function name {}, local vars, return | 2 | | Redirections | 2>&1, &>, &>>, >|, <>, fd manipulation | 2 | | Here-strings | <<< | 2 | | Heredocs | <<'EOF', <<"EOF" | 2 | | Process substitution | <(cmd) | 2 | | Arrays | ${arr[@]}, ${#arr[@]}, ${arr[i]}, arr+=(), slicing | 2 | | Brace ranges | {1..10}, {a..z}, {1..10..2} | 2 | | Traps & signals | trap 'cmd' EXIT, trap '' SIGINT | 2 | | Special variables | $?, $$, $!, $@, $#, $RANDOM | 2 | | Real-world patterns | nvm, conda, pyenv, docker, curl|bash, eval | 2-3 | | Associative arrays | declare -A | 3 | | Coprocesses | coproc | 3 | | Namerefs | declare -n | 3 |


Library

Reef is both a binary and a Rust library. You can embed it in editors, CI pipelines, or your own tools:

use reef::detect::looks_like_bash;
use reef::tr

Related Skills

View on GitHub
GitHub Stars127
CategoryDevelopment
Updated5d ago
Forks1

Languages

Rust

Security Score

95/100

Audited on Mar 25, 2026

No findings