Skip to content
osakkaPublic

About

hibr is a shell that finally behaves the way you already expect a shell to behave.

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

hibr — Highly Intuitive Bash-like Runtime

hibr is a shell that finally behaves the way you already expect a shell to behave. Familiar bash syntax, its sharpest edges resolved instead of carried forward, in about 17,500 lines of C and a 398 KB binary — under two-thirds of bash's memory, and about two and a half times its speed on a tight loop. Built with tcc, depending on nothing but libc and libdl.

The name says what it is. Highly: two-thirds of bash's memory, tight loops two and a half times faster, in a 398 KB binary — the numbers below. Intuitive: the things that make bash surprising the first time you hit them — test's word-splitting traps, $BASH_REMATCH's awkward capture, a dozen more in the decision records — fixed, so the shell does what a reader would already guess it does. Bash-like: familiar syntax you already know, not a rewrite you have to learn, and not a claim to be bash itself. Runtime: the module ABI lets a module add a protocol, not just a command — register a scheme and /dev/<name>/… works anywhere a filename does — and results come back without forking, text and JSON are manipulated without pipelines, and the prompt reads git's object store with no subprocess at all.

It is also حِبر — Arabic for ink. Every shell session, every script, every automated thing this runs is still just ink on a page in the oldest sense: it is what you write computing with.

It is not a drop-in replacement for bash. Some behaviour differs on purpose, where bash is error-prone; every one of those divergences is written down in the decision records. What it adds — nested maps, JSON, regex capture, native networking and TLS, typed functions, results without forking, declared command-line arguments, protocol-level modules, and a prompt that reads git's object store without forking anything — is the reason to use it.

hibr script.sh args...
hibr -c 'echo $((6 * 7))'
hibr --explain script.sh    # name the mistakes in it, run nothing
hibr --plan script.sh       # follow it, change nothing, list what it would do
man hibr                    # every flag, variable and exit status

Install

Every route installs the same things: hibr, its modules, man hibr, and the text desktop with a desktop launcher. hibr needs only libc and libdl; libssl and libpng are used if they are there, for TLS and images, and nothing fails without them until it is asked for.

macOS (or Linux), with Homebrew:

brew tap osakka/hibr
brew install hibr

Debian 12, Ubuntu 22.04, or newer (amd64), from the signed apt repository at osakka.github.io/hibr-apt:

curl -fsSL https://osakka.github.io/hibr-apt/hibr.gpg \
  | sudo tee /usr/share/keyrings/hibr.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/hibr.gpg] https://osakka.github.io/hibr-apt stable main" \
  | sudo tee /etc/apt/sources.list.d/hibr.list
sudo apt update && sudo apt install hibr

apt upgrade keeps it current from then on.

Fedora 36, RHEL 10, openSUSE Leap 15.6 or newer (x86_64), from the signed dnf repository at osakka.github.io/hibr-rpm (zypper addrepo takes the same file on openSUSE):

sudo curl -fsSL -o /etc/yum.repos.d/hibr.repo https://osakka.github.io/hibr-rpm/hibr.repo
sudo dnf install hibr

Arch Linux (x86_64), from the signed pacman repository at osakka.github.io/hibr-arch: trust its key once, add it to /etc/pacman.conf, and install.

curl -fsSL https://osakka.github.io/hibr-arch/hibr.asc | sudo pacman-key --add -
sudo pacman-key --lsign-key A1E3CA788A8FB02052DA22B413035BE1B1674431
printf '[hibr]\nServer = https://osakka.github.io/hibr-arch/$arch\n' | sudo tee -a /etc/pacman.conf
sudo pacman -Syu hibr

One key signs all three repositories, and the three packages hold the same files, byte for byte; dnf upgrade and pacman -Syu keep them current.

From source, anywhere with a C compiler:

git clone https://github.com/osakka/hibr && cd hibr
make                       # with tcc, the default
make CC=gcc OPT=-O2        # or with gcc: smaller and faster code
make check                 # the test suite, if you want it
sudo make install          # to /usr/local; PREFIX=$HOME/.local for yours alone

PREFIX is compiled into the binary as the place it looks for modules; make install rebuilds by itself when it is given a different one from the build before it. The desktop it installs is the window manager and what manages it, with Files, Terminal and five accessories, and one theme and two colour schemes; everything else comes from the catalogue, and catalogue install apps/ places every application in it (make install SHIP=all places the lot from this tree instead). make TLS=0 leaves TLS out entirely. deploy.sh does the same install but also runs every suite first, keeps the previous version to roll back to, and can update itself from the tree on a timer.

To take it out again: brew uninstall hibr, sudo apt remove hibr, or sudo make uninstall with the same PREFIX it went in with.

New to it? From bash to hibr, in ten minutes is the place to start.

Measurements

Measured on 0.68, on one host; the loop is while [ $i -lt 50000 ]; do i=$((i+1)); done. Times are the best of eleven runs. Memory is the shell's own VmHWM, read without forking, as the median of twenty-five runs — a single reading is worthless here, because run-to-run spread is about 180 kB either way.

hibr dash bash
binary, stripped 398 KB 122 KB 1235 KB
resident memory at startup 1852 kB 1688 kB 2900 kB
resident memory after the loop 1888 kB 1656 kB 2944 kB
the loop 87 ms 79 ms 211 ms
5000 function calls, results via := 19 ms — —
the same through $( ) 1145 ms 1018 ms 1836 ms
startup, -c true 1.67 ms 1.70 ms 2.30 ms

Read honestly. Against bash hibr is under two-thirds of the memory and two and a half times the speed on a tight loop. Against dash it is level on startup and within 10% on the loop, and about 160 kB heavier — and dash is a far smaller language, so being close is the claim, not being ahead. The loop gap was 1.7x before a round of profiling.

Where the memory goes is worth knowing: the heap at startup is 36 kB of the 1852, so memory here means the binary, and the binary means how much language there is. There is no allocator trick left that would move it.

The row that is not a near-miss is the fifth. Returning a value through $( ) costs a fork per call in every shell; := costs none, which is where the 60x comes from. That is the argument for the whole in-process design, in one line.

A full prompt with git branch, working-tree status and upstream distance cost 35 ms in a 2,600-file repository when it was measured — against 32 ms for git status --porcelain=v2 --branch alone, with no fork on top.

What it looks like

h[users][omar][role]=admin                  # maps nest, no new syntax
json parse doc "$body"; json get doc .items[0].name

fn add(int a, int b) -> int { ret $((a + b)); }
sum := add 10 32                            # a result, without forking

[[ $line =~ ^([a-z]+)=(.*)$ ]] && echo "${M[1]} is ${M[2]}"

exec 3<>/dev/tls/api.example.com/443        # sockets are descriptors
opt -o --output out path!  "Where to write" # declared arguments
args "$@"

Documentation

From bash to hibr, in ten minutes Start here: install, then each thing hibr adds, one checked example each
The language The whole language, and every place it differs from bash
Builtins All 73, what each takes and what it gives back
hibr, for a language model The whole language on one page, for a model to read; llms.txt points to it
The desktop Windows, menus and applications in a terminal, all of it hibr: a first hour, in five pictures
Everything else Data, networking, the prompt, interactive use, full-screen programs, the desktop, modules, deployment, testing
man hibr Every flag, environment variable, file and exit status

Every example in these pages is run on every build and its output compared with what the page prints (tests/531-doc-examples.t), so the documentation cannot quietly drift from the shell.

Deliberate differences from bash

Each has a record of its own explaining the reasoning and the cost, all indexed in the decisions. The ones met first:

Not implemented

bash's compound coprocess, coproc name { …; }: hibr's coproc takes a command, coproc name cmd args… -- see 0018. The line editor stores bidirectional text in logical order and leaves reordering to the terminal, so the cursor moves in logical order through Arabic text.

Source layout

include/ Public header and module ABI, internal declarations, regex declarations
src/ The shell itself — lexer, parser, expansion, execution, builtins, editor, networking
mods/ Reference modules, including the prompt and its git implementation
tests/ The harness, the scripts compared against bash or recorded, the full-screen suites, and the suite hibr runs on itself
examples/ Complete scripts showing the pieces working together
docs/ Everything above, in detail

Conventions for working on the code — naming, memory discipline, and the traps already found — are in CLAUDE.md. History is in CHANGELOG.md.

Licence

LGPL-3.0-or-later: the GNU Lesser General Public License, version 3 or any later version. See LICENSE, and COPYING for the GNU General Public License it adds its permissions to.

The name "hibr" is a trademark of Omar Sakka. The licence covers the code, not the name: a modified version or a fork is welcome under the LGPL with a name of its own. See TRADEMARKS.

About

hibr is a shell that finally behaves the way you already expect a shell to behave.

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Contributors

Languages