Skip to content

HelgeSverre/helpshell

Repository files navigation

helpshell

CI e2e Rust 1.75+ License: MIT Platforms: macOS · Linux

Docs for the shell config you wrote yourself. the shell config you forgot you wrote.

Your zsh is running thousands of aliases, functions, and completions — most of them from plugins you forgot you installed. helpshell parses your rc files, introspects your live shell, and indexes every alias, function, export, keybind, completion, and $PATH binary into a local SQLite DB you can search. Runs entirely on your machine.

Install

cargo install --git https://github.com/HelgeSverre/helpshell

Requires Rust 1.75+ and zsh on $PATH. macOS and Linux are both covered in CI. helpshell doctor reports anything missing.

Shell completions

# Zsh
mkdir -p ~/.zsh/completions
helpshell completions zsh > ~/.zsh/completions/_helpshell
# then add to ~/.zshrc (before compinit): fpath=(~/.zsh/completions $fpath)

# Bash
mkdir -p ~/.local/share/bash-completion/completions
helpshell completions bash > ~/.local/share/bash-completion/completions/helpshell

# Fish
mkdir -p ~/.config/fish/completions
helpshell completions fish > ~/.config/fish/completions/helpshell.fish

Or auto-install: helpshell completions zsh --install.

demo

What helpshell sees that grep ~/.zshrc misses

  • Plugin-defined symbols. Aliases and functions added by oh-my-zsh, zinit, or any plugin — not in your dotfiles, but live in your shell.
  • Sourced chains. Files pulled in via source ~/.config/zsh/*.zsh or [ -f x ] && source x, recursively, with cycle detection.
  • Completions and keybindings. Every completion function on $fpath, every bindkey your shell currently holds — not just the ones you typed.

Why

You accrete hundreds of aliases, functions, and helpers over the years, then forget what half of them do. Adjacent tools each cover one corner — navi for snippets, tldr for canonical commands, explainshell for one-off syntax, znt for TUI alias lookup. None of them index your own config across rc files, sourced chains, plugin-defined symbols, and live $PATH.

One rebuild — ~1s for a typical 3,500-entry zsh — and every command your shell actually has becomes a searchable, readable catalog.

How it compares

helpshell navi tldr explainshell znt
Parses your rc files
Follows source chains
Snapshots live shell state
Finds plugin-defined aliases
Indexes $PATH binaries
Indexes completions + keybinds partial
Web UI
Optional AI explanations

These tools have different scopes. helpshell is the only one that indexes your own config across every source your shell actually loads.

Quick start

helpshell rebuild        # parse rc files + snapshot live shell into ~/.local/share/helpshell/index.sqlite
helpshell web            # opens http://127.0.0.1:<random> in your browser

That's it. The UI has a sidebar (filter by kind), a fuzzy search middle pane, and a detail pane showing source file, category, docstring, and the full definition.

CLI

Every read command supports --json for piping into jq or scripts.

helpshell                       # equivalent to `helpshell web`
helpshell rebuild               # re-index
helpshell list [--kind alias]   # list entries, plain text
helpshell search <query>        # fuzzy match
helpshell show <name>           # full entry detail
helpshell explain <name>        # AI explain (requires [llm] enabled = true)
helpshell web [--port N] [--no-open]
helpshell config [--edit]       # print config path or open in $EDITOR
helpshell doctor                # diagnostics: zsh, claude, rc files, DB, paths
helpshell completions <shell>   # emit completion script (--install writes to standard path)

Configuration

First run creates ~/.config/helpshell/config.toml with sensible defaults:

[sources]
rc_files = ["~/.zshrc", "~/.zprofile", "~/.zshenv"]
follow_sourced = true
include_path_binaries = true
include_completions = true
include_keybindings = true
include_env = true
# Introspected entries whose names match these prefixes or exact names are
# dropped. Entries parsed from your rc files are never filtered. Override if
# the defaults hide something you want.
ignore_name_prefixes = ["_", "__", "nvm_", "fzf-", "fzf_", "prompt_",
                        "compdef", "compinit", "compdump", "compaudit",
                        "compinstall", "bashcompinit"]
ignore_names = ["add-zsh-hook", "is-at-least", "getent", "run-help",
                "complete", "compgen", "down-line-or-beginning-search",
                "up-line-or-beginning-search", "starship_zle-keymap-select"]

[llm]
enabled = false                                              # off by default
command = ["claude", "-p", "--model", "haiku"]
prompt_template = """..."""                                  # {kind} {name} {definition} {docstring}

[server]
port = 0                                                     # 0 = OS-assigned
auto_open_browser = true
idle_timeout_minutes = 30

[ui]
theme = "dark"
default_kind_filter = "alias"
# Click the source row in the detail pane to jump to that file:line in
# your editor. Leave empty to render as plain text. Substitutions:
#   {path} = URI-encoded absolute path, {line} = line number.
editor_link_template = ""
# Examples:
#   "vscode://file/{path}:{line}"
#   "cursor://file/{path}:{line}"
#   "zed://{path}:{line}"
#   "idea://open?file={path}&line={line}"

To turn on the AI explainer, flip enabled = true under [llm]. Make sure the binary named in command[0] is on your $PATHhelpshell doctor reports whether it is. Responses stream to the UI as the model produces them, and recent failures are cached for five minutes so repeated clicks don't re-hammer a broken model — use --force (or the Regenerate button) to bypass both caches.

Category markers

Annotate sections of your rc files with #:: and everything below attaches to that category until the next marker:

#:: Fleet cache cleanup
alias fleet-cache-list='du -sh ~/Library/Caches/Fleet'
alias fleet-cache-clean='rm -rf ~/Library/Caches/Fleet'

#:: Git shortcuts
alias gst='git status'
alias gco='git checkout'

Categories show up in the detail pane and under a "Categories" section in the left rail, where clicking one narrows the list (combines with the kind filter). A paragraph break — two consecutive blank lines — closes a category block, so markers don't leak onto unrelated definitions further down the file.

Architecture

Cargo workspace, three crates + a no-build-step vanilla-JS frontend:

  • helpshell-core — parser, introspector (zsh -i -c), merger, SQLite indexer, fuzzy query layer (nucleo-matcher), LLM explainer.
  • helpshell-server — axum server with a rust-embed frontend, auto-rebuild-if-stale on start, idle-timeout watchdog.
  • helpshell-cli — thin clap dispatcher.
rc files ──► parser ──┐
                      ├──► merger ──► dedup ──► hash ──► SQLite
zsh -i -c ──► live  ──┘                                        │
                                                               ▼
                                                    query ──► JSON ──► UI

The full spec is in docs/design.md. Prior art research is in docs/research.md. Implementation plans for each milestone are in docs/plans/.

Development

cargo test --workspace                                       # 130 Rust tests (3 ignored — need live zsh / claude)
cargo clippy --workspace --all-targets -- -D warnings        # clean
cargo build --release                                        # release binary
just e2e                                                     # 21 Playwright tests driving the UI (sandboxed)

# Iterate on the frontend without rebuilding the binary:
HELPSHELL_FRONTEND_DIR=$(pwd)/frontend cargo run -- web --port 17980 --no-open

About

Turn your messy zsh config into a searchable local command catalog.

Topics

Resources

License

Stars

Watchers

Forks

Contributors