A modern, fish-inspired interactive shell written in Common Lisp.
nshell is an interactive shell that puts the interactive experience first: real-time syntax highlighting, history-aware autosuggestions, fish-style abbreviations, and a fast, context-aware completion engine — all built on a clean, test-driven Common Lisp core (8,800+ checks) and a reproducible Nix build.
Status: early development (0.4.x). The interactive editor and core pipeline execution are solid and heavily tested. The shell language is a growing subset of POSIX/fish semantics — see Roadmap for what is and isn't supported yet. nshell is usable as a daily interactive shell for common workflows; it is not a script-compatible
/bin/shreplacement.
- Syntax highlighting as you type — commands, strings, operators, and paths are colorized live.
- Autosuggestions from your history, fish-style, accepted with
→/Ctrl-F. - Abbreviations (
abbr) that expand inline as you type — keep your muscle memory, type less. - Context-aware completion — a knowledge base of commands/flags plus
filesystem completion, with common-prefix
Tabextension and a candidate menu. - Rich line editing — Emacs keybindings, kill-ring & yank, multi-level
undo/redo, multiline editing, and incremental history search (
Ctrl-R). Optional vi key bindings (NSHELL_VI_MODE=1): normal-mode motions, counts, operators (dd,cw, …), visual selection, and insert/append. - Configurable prompt — hostname, working directory, git branch/dirty status, command duration, and exit code, with theming.
- Job control — background jobs (
&),jobs,fg,bg,disown. - Pipelines & redirection —
|,>,>>,<,<<,<<<, logical&&/||, and command sequencing. - Control flow & functions —
if,for,while,switch,begin/end, and user-definedfunctions. - Reproducible build — a single statically-dumped SBCL image via Nix;
nix runand you're in.
With Nix (flakes enabled), run nshell without installing anything:
nix run github:takeokunn/nshellOr build a binary into your profile:
nix profile install github:takeokunn/nshell
nshell
man nshell # the manual page is installed alongside the binarynshell -c 'echo hello | string upper'nshell examples/greet.nsh WorldScript files support multiline blocks (functions, if/for/while/switch),
comments, and a #! shebang; arguments after the script name are available as
$argv. See examples/ for a runnable sample.
Usage: nshell [--help] [--version] [-c COMMAND [ARGS...]] [SCRIPT [ARGS...]]
Without arguments, nshell starts an interactive shell when stdin is a terminal
and reads batch input from stdin otherwise.
With -c/--command, nshell executes COMMAND once in batch mode; trailing ARGS are available as $argv.
With SCRIPT, nshell runs the script file; trailing ARGS are available as $argv.
nshell builds with SBCL and ASDF. The supported and tested path is Nix:
git clone https://github.com/takeokunn/nshell
cd nshell
nix build # produces ./result/bin/nshell
nix flake check --print-build-logs
nix develop # dev shell with SBCL + cl-weaveInside nix develop, you can load the system into a REPL:
(asdf:load-system :nshell)
(nshell:main)alias, abbr, bg, cd, complete, contains, count, disown, echo,
exec, exit, export, false, fg, function, help, history, jobs,
ls, not, pipeline-graph, pwd, read, seq, set, source, string,
test, true, type, which.
pipeline-graph 'CMD | CMD ...' renders a typed pipeline as a Graphviz DOT
graph (or a Mermaid flowchart with --mermaid) without executing it — a
diagnostic built on the cl-dataflow computation-graph toolkit. Quote the
pipeline so the shell passes it as a single argument rather than running it,
e.g. pipeline-graph 'cat access.log | grep 404 | wc -l'.
Run help inside nshell for details.
nshell follows a domain-driven, layered design. Each layer depends only on the layers beneath it:
src/
├── domain/ Pure shell logic: parsing, expansion, completion,
│ history, prompting, job-control — no I/O.
├── application/ Use cases: builtins, pipeline execution, job management.
├── infrastructure/ ACLs over the OS: syscalls, PTY, signals, terminal I/O,
│ persistence. SBCL-specific code is isolated here.
└── presentation/ The REPL, line editor (input-state reducer), rendering,
highlighting, autosuggestions, completion UI.
The REPL is structured as a continuation-passing / trampoline loop: each
keystroke runs a pure reducer over an immutable input-state, and rendering is
derived from that state. This keeps the interactive core deterministic and
unit-testable without a terminal.
nshell builds on the nerima-lisp Common Lisp toolkit family, each wired at the
layer where it fits the domain-driven design:
- cl-parser-kit — its
rule-based tokenizer and Pratt (operator-precedence) parser drive
$((...))arithmetic, which parses to an AST and then evaluates (adding**, bitwise& | ^ ~, shifts<< >>, and the ternary?:). - cl-dataflow — renders
pipelines as validated computation graphs (
pipeline-graph) and models the job lifecycle as an analyzable state machine. - cl-boundary-kit — makes the REPL edge's OS effects (hostname, working directory, clock) explicit, swappable boundaries, so the prompt and command timing are deterministic under test.
- cl-cli — declaratively describes
the
nshellcommand line (--help/--version/-c/script dispatch). - cl-tty-kit — provides Unicode-correct display-width, truncation, and padding, plus the ANSI/SGR escape vocabulary used by rendering, prompt, and completion.
nshell runs entirely on cl-weave, with two complementary suites exposed through Nix checks:
nshell/test— the primary regression suite (~1,290 cases,describe/it/expect).nshell/weave— a focused suite that exercises the completion engine's cl-prolog knowledge base with property-based tests, fixtures, benchmarks, and direct Prolog queries (findall, negation-as-failure, foreign predicates) plus thecl-prolog/weavequery bridge.
Run the same hermetic Linux/macOS gate used by CI (it runs both suites):
nix flake check --print-build-logsRun only the current platform's test derivation:
nix build .#checks.$(nix eval --impure --raw --expr builtins.currentSystem).testRun the full non-sandboxed integration suite when changing PTY, subprocess, terminal, or job-control behavior. This covers the real-PTY interactive smoke, Ctrl-C recovery, and job-control lifecycle checks that are intentionally skipped inside hermetic Nix builds:
nix develop -c sbcl --non-interactive \
--eval '(require :asdf)' \
--eval '(push (truename "./") asdf:*central-registry*)' \
--eval '(asdf:test-system :nshell/test)'Generate an HTML coverage report for the same suite:
nix develop -c sbcl --script scripts/coverage.lispThe report is written to coverage/cover-index.html by default. Set
NSHELL_COVERAGE_DIR to redirect the output.
Run the cl-weave suite on its own (the weave alias in nix develop, or
directly). The runner self-registers sibling ../cl-weave and ../cl-prolog
checkouts, so no extra environment setup is needed:
sbcl --script scripts/weave.lispUnit, integration, property-based, and end-to-end tests live under tests/.
New shell-language, expansion, completion, job-control, and input-state changes
should include focused regression tests plus the relevant property or PTY
coverage when behavior crosses process, terminal, or parser boundaries. See
CONTRIBUTING.md for test-selection expectations.
nshell is converging on world-class interactive-shell parity. Near-term focus:
- Shell language depth — richer list variables and explicit semantics
around compound expansions.
(Quoting, parameter expansion with defaults, required checks, substring
slicing, and patterns, arithmetic
$((...))— including**, bitwise, shift, and ternary operators — brace expansion, command substitution$(...)/(...), fd redirections2>/2>&1/&>, here-docs<<, here-strings<<<, and function arguments via$argv/$argv[N]are done.) - Job control hardening — robust foreground process-group handling so
Ctrl-C/Ctrl-Zreliably interrupt and suspend pipelines. - Completion intelligence — broader command metadata and higher-fidelity flag/value completion.
- Distribution — nixpkgs, Homebrew, and prebuilt release binaries.
See CHANGELOG.md for released changes.
For release qualification, see PUBLIC_READINESS.md.
Contributions are welcome. Please run nix flake check --print-build-logs
before opening a pull request; CI runs that hermetic gate on Linux and macOS
and also runs the full non-sandboxed integration suite on Linux. See
CONTRIBUTING.md for style, test, semantics, and issue-reporting
expectations.
Please report vulnerabilities privately instead of opening a public issue. See
SECURITY.md for the supported scope, report contents, and disclosure process.
MIT © the nshell authors.