Skip to content

Latest commit

 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NovaShell

CI Release License: MIT Zig

A modern, lightweight, cross-platform command-line shell, written in Zig.

NovaShell is inspired by PowerShell's ergonomics — but it isn't trying to clone every PowerShell feature. The goal is a shell that's fast, visually clean, covers the commands you actually use every day, and has its own identity.

⚡ NovaShell v0.1.0
───────────────────────────────────────
📂 /home/nova/projects
❯

Why NovaShell?

Most cross-platform shells fall into two camps: decades-old and unopinionated about visuals (bash, zsh), or feature-rich but heavy and Windows-centric (PowerShell). NovaShell is a bet on a third option — a small, fast, native binary with a genuinely nice-looking prompt out of the box, that runs the same way on Windows, Linux, and macOS, without needing a runtime installed or a 50MB download. If you've ever spent an evening configuring Starship/oh-my-posh on top of your shell just to get a prompt that looks decent, NovaShell tries to make that the default instead of an add-on.

How does it compare?

NovaShell bash/zsh PowerShell Nushell
Written in Zig C C# (.NET) Rust
Cross-platform ✅ native mostly (Unix-first)
Colored prompt/theme out of the box ❌ (needs a framework) partial
Startup time fast (no runtime) fast slower (.NET) fast
Scripting language — (not yet a goal) POSIX shell full .NET-backed language structured/typed
Binary size ~400KB stripped varies large (.NET runtime) larger

NovaShell isn't trying to win on scripting power — it's trying to win on being fast, good-looking, and easy to reason about for everyday interactive use. See Known simplifications & limitations for an honest list of what it doesn't do yet.

Status: All 12 phases of the development plan are complete, plus every "extra feature" from the original spec. See Development plan & status below.


Table of contents


Feature list

Core shell

  • Interactive REPL (Read-Eval-Print Loop)
  • Executes external programs on $PATH (git, node, npm, python, code, anything else)
  • Relative and absolute path support everywhere paths are used
  • Friendly, colored error messages instead of raw Zig errors or crashes (missing command, permission denied, bad exit code, etc.)
  • Graceful fallback to plain line-buffered input when stdin isn't a real terminal (piped input, scripts, CI) — everything still works, just without live editing

Line editing & history

  • A real interactive line editor: type, Backspace, Enter
  • Command history recalled with ↑ / ↓, persisted across sessions to ~/.novashell_history
  • Consecutive duplicate commands aren't stored twice
  • Ctrl+C cancels the current line without exiting the shell
  • Ctrl+D exits cleanly on an empty line (same convention as bash/zsh)

Tab completion

  • Completes builtins, aliases, and $PATH executables in command position
  • Completes files and directories everywhere else — directories get a trailing / (no space) so you can keep tabbing deeper; finished files/commands get a trailing space
  • Multiple matches complete as far as their shared prefix allows, or list all options if there's nothing more in common

Directory navigation

  • cd [path] — relative, absolute, or no argument at all (goes to your home directory)
  • pwd — prints the current working directory

Built-in commands

"Did you mean...?" suggestions

  • Typing an unknown command checks it against every builtin, alias, and $PATH executable using edit-distance matching, and suggests the closest one if it's a plausible typo

Environment variables

  • $VAR, ${VAR}, and %VAR% all expand in command arguments
  • Unset variables expand to nothing rather than erroring out the whole command

Visual design

  • Full ANSI color support with automatic detection — colors are disabled automatically when output isn't a real terminal, or when NO_COLOR is set
  • Two-line styled prompt: 📂 <colored current directory> then a colored glyph
  • Colorful startup banner
  • Colored error/warning output, distinct from normal command output

Themes

  • Four built-in palettes: default, ocean, sunset, mono
  • Individual color overrides (prompt_color, glyph_color) on top of whichever theme is active

Configuration

  • Config file at ~/.novashellrc (or %USERPROFILE%\.novashellrc on Windows), auto-created with a commented-out example on first run
  • Theme selection and color overrides
  • User-defined aliases, including argument passthrough (alias ll = ls -la + typing ll /tmp runs ls -la /tmp)
  • Alias loops are detected and reported instead of hanging
  • Unrecognized config lines are reported as warnings at startup, not silently ignored and not fatal

Cross-platform

  • Builds natively for Windows, Linux, and macOS from a single codebase
  • Windows raw-mode terminal input uses ENABLE_VIRTUAL_TERMINAL_INPUT, so arrow keys/Tab/Ctrl+C are decoded through the exact same code path as Unix terminals — one line editor, not two

Requirements

  • Zig 0.16.0 or newer

If you don't have Zig installed, the easiest cross-platform option is the ziglang PyPI package, which ships a prebuilt Zig binary:

pip install ziglang --break-system-packages
python3 -m ziglang build run   # use this instead of `zig build run` below

If you already have Zig on your PATH normally, just use zig directly as shown in the rest of this doc.

Getting started

# Build (output goes to zig-out/bin/novashell or novashell.exe)
zig build

# Build and launch immediately
zig build run

# Run the test suite
zig build test

Cross-compiling to another platform works out of the box, no extra SDKs:

zig build -Dtarget=x86_64-windows -Doptimize=ReleaseSafe
zig build -Dtarget=x86_64-linux   -Doptimize=ReleaseSafe
zig build -Dtarget=aarch64-macos  -Doptimize=ReleaseSafe

(ReleaseSafe is what release builds use — see Installing a release build — it keeps bounds/overflow checks on, trading a little speed for turning bugs into a caught error instead of undefined behavior. ReleaseFast is available too if you want to trade that safety net for the last bit of performance.) Building all five release targets at once, packaged into archives: scripts/release.sh.

The first time you run NovaShell, it creates ~/.novashellrc for you — see Configuration.

Installing a release build

If you'd rather not build from source, grab the archive for your platform from the releases page — or, to build them yourself locally exactly as CI does:

scripts/release.sh          # builds + packages all 5 platform archives into dist/

Each archive contains the novashell binary alongside the README, LICENSE, and CHANGELOG. A dist/SHA256SUMS file is generated alongside them — worth checking after downloading:

sha256sum -c SHA256SUMS      # Linux
shasum -a 256 -c SHA256SUMS  # macOS

Windows — unzip novashell-vX.Y.Z-x86_64-windows.zip, then either run novashell.exe directly from that folder, or move it somewhere already on your PATH (or add the folder to PATH yourself) so you can launch it from anywhere. Since this binary isn't code-signed, Windows SmartScreen may warn about it the first time — click "More info" → "Run anyway" if you trust the source it came from.

macOS — extract the tarball (tar xzf novashell-vX.Y.Z-*-macos.tar.gz), then chmod +x novashell and move it into somewhere on your PATH, e.g. /usr/local/bin. Since this binary isn't notarized, Gatekeeper will likely block it the first time you run it — either right-click → Open once to approve it, or run xattr -d com.apple.quarantine novashell after extracting.

Linux — extract the tarball, chmod +x novashell, then move it onto your PATH (e.g. ~/.local/bin or /usr/local/bin).

Using NovaShell

Running commands

Type a command and press Enter, same as any shell:

❯ git status
❯ node app.js
❯ python script.py --flag value
❯ cd ../other-project

Arguments with spaces need quotes (single or double both work):

❯ cd "Program Files"
❯ code 'my project'

Keyboard shortcuts

Key Action
Tab Complete commands, aliases, or file/directory paths
/ Browse command history
Ctrl+C Cancel the current line, get a fresh prompt
Ctrl+D Exit NovaShell (only when the line is empty)
Backspace Delete the last character typed

Typing exit or quit and pressing Enter also exits.

Built-in commands

Command What it does
cd [path] Change directory. No argument → go to your home directory.
pwd Print the current working directory.
clear / cls Clear the screen.
help List built-in commands and key shortcuts.
about What NovaShell is, and where its files live.
version Print the NovaShell version.

Everything else (git, node, npm, python, code, ...) is run as an external program from $PATH, with its output shown directly — NovaShell doesn't try to reinterpret it.

Environment variables

Reference environment variables in any command's arguments:

❯ echo $HOME
❯ echo ${HOME}/projects
❯ cd %USERPROFILE%

An unset variable just expands to nothing, rather than causing an error.

Configuration

NovaShell reads ~/.novashellrc (%USERPROFILE%\.novashellrc on Windows) on startup. If the file doesn't exist yet, NovaShell creates one for you with everything commented out, so there's something to find and edit:

# NovaShell configuration
#
# Lines starting with '#' are comments. Blank lines are ignored.

# Pick a theme: default, ocean, sunset, mono
# theme = default

# Override individual prompt colors (optional; takes priority over
# the theme). Available colors: black, red, green, yellow, blue,
# magenta, cyan, white, and a bright_ version of each.
# prompt_color = cyan
# glyph_color = bright_magenta

# Aliases: alias <name> = <command...>
# alias ll = ls -la
# alias gs = git status

Uncomment and edit whatever you want. A line NovaShell doesn't understand (a typo'd key, an unknown theme name) is reported once at startup as a warning — it won't stop the shell from starting.

Themes

Theme Feel
default Cyan path, magenta prompt glyph
ocean Blues and cyans
sunset Warm yellows, reds, and magenta
mono No color at all — bold/dim only

Set with theme = <name> in the config file. prompt_color and glyph_color override just those two elements on top of whichever theme is active.

Aliases

alias ll = ls -la
alias gs = git status
alias gohome = cd $HOME
  • Extra arguments typed after the alias name are appended to its expansion: with alias ll = ls -la, typing ll /tmp runs ls -la /tmp.
  • Aliases can use environment variables (alias gohome = cd $HOME).
  • Alias loops (alias a = b where b eventually expands back to a) are detected and reported instead of hanging the shell.

How it works (architecture)

Project layout

build.zig, build.zig.zon   Build system + package metadata.
LICENSE, CHANGELOG.md       Release documentation.
CONTRIBUTING.md, CODE_OF_CONDUCT.md   Contributor docs.
scripts/release.sh          Builds + packages all platform release archives.
.github/workflows/ci.yml         Build + test on every push/PR.
.github/workflows/release.yml    Publishes a GitHub Release on a version tag push.
.github/ISSUE_TEMPLATE/          Bug report / feature request forms.
src/
  main.zig            Entry point — wires everything together.
  repl.zig             The Read-Eval-Print Loop and interactive line editor.
  parser.zig           Turns a line of input into a structured command.
  executor.zig         Runs a parsed command: env var + alias expansion, builtin or child process.
  context.zig           Shared execution context threaded through the above.
  commands/
    builtins.zig         cd, pwd, clear/cls, help, about, version.
    suggest.zig           "Did you mean...?" typo suggestions (edit distance).
  ui/
    banner.zig            Startup banner.
    prompt.zig             The two-line styled prompt.
    colors.zig              ANSI color helpers + terminal/NO_COLOR detection.
    theme.zig                Named color palettes.
  history/
    history.zig            Command history: recording, persistence, recall.
  config/
    config.zig              ~/.novashellrc loading: theme, colors, aliases.
  completion/
    completion.zig          Tab-completion for commands and paths.
  utils/
    version.zig              Version string, in one place.
    env.zig                   Home-directory lookup (cross-platform).
    tty.zig                    Raw terminal mode + keystroke decoding.

Design notes worth knowing

  • NovaShell is a shell, not a terminal emulator. It runs inside whatever terminal you launch it from (Windows Terminal, iTerm2, GNOME Terminal, tmux, SSH, VS Code's integrated terminal, ...) and talks to it via ANSI escape codes — exactly like bash, zsh, fish, and PowerShell itself all do. There's no separate GUI window.
  • One line editor for every platform. utils/tty.zig puts the terminal into raw mode (termios on Unix-likes, the Win32 console API on Windows) and, on Windows, also turns on ENABLE_VIRTUAL_TERMINAL_INPUT — which makes Windows' console send arrow keys and other special keys as the same ANSI escape sequences Unix terminals use. That means the actual key-decoding and line-editing logic in repl.zig is written once and shared across platforms; only entering raw mode differs per OS.
  • Everything that can go wrong during a command is a printed message, not a crash. A missing program, a bad path, a permission error, a nonzero exit code — executor.zig and the builtins turn all of these into a friendly colored line of output. Zig errors are reserved for things actually wrong with NovaShell itself (out of memory, a broken pipe), which is what still propagates up and would stop the shell.
  • Config-driven, not hardcoded. The active theme and alias table live in one Config struct threaded through a shared Context, so the prompt, banner, error messages, and command dispatch all read from the same source instead of each having their own copy of "what color is an error" or "what does ll expand to."

Known simplifications & limitations

Being upfront about what's not here yet:

  • No cursor movement within a line. Left/Right arrows don't move the cursor — editing only happens at the end of the line you're typing. History recall and Tab completion both work fine within that constraint; only "go back and fix a typo in the middle of what you typed" isn't supported yet.
  • Quoting doesn't suppress environment variable expansion. Unlike bash, '$HOME' still expands — the parser doesn't currently track which quote style produced each argument.
  • No pipes or redirection (|, >, <) yet — each line runs as a single command.
  • Command-name completion doesn't check the executable bit. It lists files in each $PATH directory by name; Windows has no equivalent concept anyway, and checking properly on POSIX would mean an extra filesystem call per candidate.
  • Windows and macOS are verified by successful cross-compilation, not by running the binary on real hardware. This project has been developed and runtime-tested on Linux. utils/tty.zig's Windows console-mode handling (talking to kernel32 directly) is the piece most worth double-checking first if you have access to a Windows machine.

Contributing

Bug reports, feature ideas, and PRs are welcome — see CONTRIBUTING.md for how to get set up, what to check before opening a PR, and a few genuinely approachable places to start. This project follows a Code of Conduct.

Development plan & status

Built incrementally, each phase reviewed before the next started:

  1. Project setup ✅ — build system, module skeleton, cross-compile check.
  2. REPL ✅ — interactive read/print loop with graceful exit handling.
  3. Command parser ✅ — whitespace + quote-aware argv splitting.
  4. Process execution ✅ — spawns external programs, forwards stdio, reports exit codes.
  5. cd implementation ✅ — plus pwd; relative, absolute, and home-directory paths.
  6. Prompt UI ✅ — two-line styled prompt (📂 path, then ) and welcome banner.
  7. Colors ✅ — ANSI helpers with TTY detection and NO_COLOR support.
  8. Command history ✅ — arrow-key recall, persisted to ~/.novashell_history.
  9. Auto-completion ✅ — Tab-completes commands, aliases, $PATH executables, and file/directory paths.
  10. Config system ✅ — ~/.novashellrc, auto-created on first run; theme selection, color overrides, aliases.
  11. Themes ✅ — four built-in palettes, switchable via config.
  12. Packaging and release ✅ — cross-platform release archives, checksums, and a GitHub Actions release workflow.

Plus, beyond the phase list, everything from the original feature spec:

  • clear/cls, help, about, version builtins ✅
  • "Did you mean...?" typo suggestions ✅
  • Environment variable expansion ($VAR, ${VAR}, %VAR%) ✅

How releases are cut

  1. Bump the version in build.zig.zon and src/utils/version.zig, and add a new entry at the top of CHANGELOG.md.
  2. git tag vX.Y.Z && git push origin vX.Y.Z.
  3. .github/workflows/release.yml picks up the tag, builds all 5 platform targets with scripts/release.sh, and opens a draft GitHub Release with the archives and checksums attached — reviewed and published by hand, not auto-published, so nothing ships without a final look.

Building the same artifacts locally without pushing anything: scripts/release.sh (requires Zig on PATH, or the ziglang pip package as a fallback).

License

MIT — see the LICENSE file. (The copyright holder name in there is a placeholder; swap in your own name/org before publishing.)

About

A fast, native, cross-platform shell written in Zig with tab completion, history, themes, and aliases.

Topics

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages