A terminal file manager (TUI) written in Rust using ratatui + crossterm.
sb (Shell Buddy) is a keyboard-driven explorer focused on fast local navigation with optional integrations for previews, archive handling, searching, remote mounts, and lightweight Git workflows.
- In-TUI Git workflow — diff preview → status review → commit → push → optional tag, all without leaving the file manager (
G) - AI commit messages — draft a commit message from the diff with one keypress (Groq or GitHub Models), then edit before committing (
Ctrl+Gin the commit prompt) - AI folder organization — propose grouping the current folder's files into new or existing subfolders, review the plan, then confirm before anything moves (
Ctrl+O) - Custom shortcuts — rebind any of the 42 browsing commands from the built-in Shortcuts panel; changes persist in the config and the help screen and footer pills update to match
- Inline path filters — type
^prefix,suffix$, or~containsdirectly in the path bar to live-filter the listing (Tab) - Integration manager with one-key install — see which optional tools are missing and install them via Homebrew without leaving the TUI (
I) - Age encryption — protect or decrypt
.agefiles in-place with a single keypress (p) - Per-file notes — attach notes to any file, stored in a hidden
.sbfile per directory (Ctrl+n) - tmux-aware splits —
iopens a shell + preview pane;Eopens a shell + editor pane (falls back tozellijwhen tmux isn't installed) - Clipboard edit —
Ctrl+eopens the current clipboard contents in$EDITORfor quick manipulation - CLI list/tree modes —
sb -l,sb -t,sb -l2produce TUI-consistent column output;sb <file>skips the TUI and opens with the best available viewer
Build and Run
cargo build
cargo runRelease build:
cargo build --releaseRelease binary path:
target/release/sb
List mode examples:
# Current directory
sb -l
# Include hidden entries
sb -a
sb -la
# Recursive display size + percent share columns
sb -l --total-size
# Full tree output
sb -t
# Tree output limited to depth 2
sb -l2
sb -l 2
# Path can appear before or after --total-size
sb -la /var/log --total-size
sb --total-size -l /var/log
# Open a file directly with the best available previewer/viewer
sb README.md
sb diagram.mmd
# Open a file with pager mode enabled
sb -l README.md
# Open a file in $EDITOR (fallback: nano)
sb -e README.mdCLI List Mode
-l [PATH]: list directory entries and exit.-a [PATH]: same as-l, but includes hidden files.-la [PATH]: same as-l, but includes hidden files.-e [FILE]: open file in$EDITOR(fallback:nano) and exit.-t [PATH]: tree-list recursively (full depth) and exit.-lN [PATH]/-l N [PATH]: tree-list to depthNand exit.--total-size: when used with-l,-a, or-la, shows recursive display size for each entry and a%column with that entry's share of the listed total.
Notes:
PATHis optional and can be placed after-l/-a/-laor after--total-size.- The list output reuses the file manager's auto-calculated owner/group column widths for consistent alignment.
- When invoked as
sb <FILE>, the app skips the TUI and opens the file directly with best-available viewer output (no pager). - When invoked as
sb -l <FILE>, direct file mode uses pager-enabled output.
Installation
cargo install shell-buddybrew install hjelev/tap/sbgit clone https://github.com/hjelev/sb.git
cd sb
cargo install --path .Prebuilt binaries and the auto-installer script are available in GitHub Releases. Use the installer there if you want the fastest setup without building from source.
Core Controls
The keys below are the defaults — most browsing commands can be rebound from the Shortcuts panel (see Custom Shortcuts below). Structural keys (arrows, Enter, Esc, Tab, Space, PageUp/PageDown, Home/End, digit bookmarks, and the fixed F-key/Del alternates) are not rebindable.
q/Esc: quit- ```: toggle modes
Enter/Right: open entry / preview fileLeft/Backspace: go to parent / leave mounted view- mouse left-click: select clicked entry
- mouse double left-click: open clicked entry (same behavior as
Right) - mouse right-click: go to parent / leave mounted view (same behavior as
Left) Up/Down/PageUp/PageDown/Home/End: navigationSpace: mark/unmark current entry*: toggle all markscorF5: copy to internal clipboardCtrl+c: copy selected full path(s) to system clipboardCtrl+e: edit system clipboard text in$EDITORv: pastem: move (cut+paste behavior) from internal clipboardd: delete (with confirmation)x: toggle executable bit on selected file(s)p: protect/unprotect file withage(.age)F2orr: rename (or bulk rename withvidirwhen multiple are marked)eorF4: open in$EDITOR(orhexeditfor binary if available)E: split tmux (or zellij) session with shell on the left and$EDITORon the right (Ctrl+eis clipboard edit)n: new file or folder (folder starts with/)Ctrl+n: add/edit note for selected item(s)t: open~/.todoin$EDITOR(creates it if missing)Z: archive create/extract flowC: compare marked file vs cursor file withdeltaG: Git commit workflow with diff preview,git status, commit/push, and optional post-push tag creationo: open with system GUI opener (openon macOS,xdg-open/gio openelsewhere)f: open Search overlay (filename search; uses built-in search iffzfis missing)g: content search (rg, optionalfzfhandoff; falls back to built-in Search content mode whenrgis missing);: open command prompt, run shell command, then wait for keypress before returning to TUIS: SSH/rclone remote pickeri: split shell (left) +lesspreview (right 30%)I: integrations panelb: bookmarks panelT: themes panelw: download a URL into the current folderCtrl+z: drop to interactive shell in current directory/(in browsing): quick-filter the current folder listing (not available in dual panel mode)Tab(in browsing): edit current path inline; supports/path/^prefix,/path/suffix$, and/path/~containsfiltersTab/Shift+Tabin Help/Search/Bookmarks/Remote Mounts/Sorting/Integrations: cycle tabs forward/backwards: toggle folder size calculation in listingCtrl+s: open sort mode menu+: expand selected/marked non-empty folder(s) by one tree level-: contract selected/marked folder(s) by one tree level- quick
++: expand selected/marked non-empty folder(s) to max depth - quick
--: collapse all opened folders in tree view 0-9: jump to bookmark (SB_BOOKMARK_0..9).: toggle hidden files~: jump to homeh: help overlay
Custom Shortcuts
Open the help overlay (h) and cycle with Tab/Shift+Tab to the Shortcuts tab (it is the last tab, so h followed by Shift+Tab gets there directly).
The panel lists every rebindable browsing command grouped by category, showing the current key and the default:
Up/Down/PageUp/PageDown/Home/End: move the selectionEnter(orSpace): capture a new key — the next key you press becomes the binding;Esccancels the captureBackspace/Del: reset the selected command to its default keyEsc/q: close the panel
Rules:
- Reserved structural keys (arrows,
Enter,Esc,Tab,Space,PageUp/PageDown,Home/End, digits, and the fixedF2/F4/F5/Delalternates) cannot be assigned. - A key already used by another command is rejected with a warning naming the conflicting command — rebind that one first if you want to swap keys.
- Changes apply immediately and persist as
shortcut_<id> = <combo>lines in~/.config/sb/config(e.g.shortcut_rename = u,shortcut_sort_menu = ctrl+t). You can edit these lines by hand; invalid, reserved, or conflicting entries fall back to defaults on load. - The help screen and the footer shortcut pills always reflect the active bindings.
Search Overlay Functions
When Search is open (f or fallback from g):
Up/Down: move result selectionEnter: open selected matchEsc: close SearchCtrl+t: toggle scope betweenFilenameandContent- Query supports regex forms:
re:patternor/pattern/i - Content-mode results render as
path:linewith highlighted matching snippets - Content-mode scanning runs asynchronously (UI remains responsive)
Content limits editor (content scope):
Ctrl+l: open/close limits editorUp/Down: select which limit to editLeft/Rightor-/+: decrease/increase selected limitShift+ adjust: 10x stepr: reset limits from environment/default valuesEnter/Esc: close limits editor
Path Editing and Filters
Press Tab while browsing to edit the current path in place.
- Enter a directory path and press
Enterto jump there. - Add a suffix filter to keep the current directory but narrow visible entries:
/some/path/^foo: names starting withfoo/some/path/bar$: names ending withbar/some/path/~baz: names containingbaz
Escfrom path-edit mode clears the active filter and returns to browsing.
The active filter remains visible in the header until you change directories.
Git Workflow
Press G (or Ctrl+G) in a Git working tree to:
- preview the current diff (
deltaside-by-side when available) - view
git status - confirm whether to continue
- enter a commit message inside the TUI — or, once in the commit prompt, press
Ctrl+Gagain to generate one with AI from the current diff (the draft stays editable;Ctrl+Gagain retries) - auto-run
git add --all,git commit, andgit push origin HEAD - optionally press
timmediately after a successful push to create and push a tag
When tagging, the tag input box is prefilled from the latest reachable Git tag when one exists.
AI commit messages use an OpenAI-compatible chat-completions API (Groq or GitHub Models). Pick the provider, model, and API key in the Settings panel (open the help overlay with h, then Tab/Shift+Tab to reach Settings). If no key is stored there, the provider's environment variable is used as a fallback (GROQ_API_KEY or GITHUB_TOKEN).
Getting an API token:
- Groq: sign up at console.groq.com, then create a key on the API Keys page. Groq has a free tier. Paste the key into the Settings panel, or export it as
GROQ_API_KEY. - GitHub Models: create a fine-grained personal access token (or a classic token) — no extra scopes are required, just a valid token from a GitHub account with access to GitHub Models. Paste it into the Settings panel, or export it as
GITHUB_TOKEN.
AI Organize
Press Ctrl+O on the active pane's current folder to:
- send the folder's top-level entry names to the same AI provider configured for commit messages (see Settings above)
- review the proposed plan — new or reused subfolders and which entries would move into each
- press Confirm to create the folders and move the entries, or Cancel/
Escto discard the plan with no filesystem changes
Nothing is applied until you explicitly confirm. Hidden (dot) entries are never included, and any AI-proposed name that doesn't match a real entry, or any folder name containing a path separator, is dropped before the plan is even shown.
Integrations
Required behavior:
less: file viewing fallback$EDITOR: file editing command (defaults tonanoif unset)
Optional integrations (auto-detected, toggle in I panel):
-
In the Integrations panel, pressing
Enteron a missing integration asks for confirmation and can install with Homebrew when available (macOS and Linux/Homebrew). -
Press
/inside the Integrations panel to search/filter the integration list. -
VCS:
git -
Viewers/previews:
bat,glow,mmdflux,jnv,csvlens,hexyl,chafa,viu,sox,pdftotext,asciinema,links -
Diff/edit helpers:
delta,hexedit,vidir,tmux,zellij -
Archives:
zip/unzip,tar,7zfamily (7z/7zz/7zr),rar/unrar,fuse-zip,archivemount -
Security:
age -
Remote mounts:
sshfs,rclone -
Search:
rg,fzf -
Clipboard backends:
wl-copy/wl-paste,xclip,xsel,pbcopy/pbpaste
Remote picker (S) also lists existing local mounted folders discovered under:
/media/$USER/run/media/$USER/mnt/run/user/$UID/gvfs
If an optional tool is not available, the feature is skipped or falls back gracefully.
Environment Notes
NERD_FONT_ACTIVE=1: enable Nerd Font iconsNO_COLOR=1: disable file name colors (modifiers like bold/dim still apply)TERMINAL_ICONS=0: hide all file icons (Nerd Font glyphs and emoji)EDITOR: editor command used bye/F4,E,Ctrl+e, andtSB_BOOKMARK_0...SB_BOOKMARK_9: bookmark directoriesSB_SEARCH_CONTENT_MAX_FILES: built-in Search content-mode max files scanned (default:20000)SB_SEARCH_CONTENT_MAX_HITS: built-in Search content-mode max matches returned (default:2000)SB_SEARCH_CONTENT_MAX_FILE_BYTES: built-in Search content-mode per-file byte cap (default:2097152/ 2 MiB)GROQ_API_KEY: API key fallback for AI commit messages when the Groq provider is selected and no key is stored in configGITHUB_TOKEN: API key fallback for AI commit messages when the GitHub Models provider is selected and no key is stored in config
Persistent config (~/.config/sb/config, key = value) also supports:
disable_clock = true: replace the header clock with a disk-usage pillai_provider = groq: AI commit message provider (groqorgithub; defaultgroq)ai_model = ...: model for AI commit messages (leave empty to use the provider default)ai_api_key = ...: API key for AI commit messages (overrides the provider environment variable; usually set via the Settings panel)shortcut_<id> = <combo>: custom key binding for a browsing command (e.g.shortcut_rename = u,shortcut_sort_menu = ctrl+t; usually set via the Shortcuts panel)- Nerd Fonts and file name colors can be toggled live from the Themes menu (the choice is persisted here alongside the active theme and view mode)
Shell Integration
To enable automatic directory change on exit, add the following function to your shell configuration file (e.g., ~/.bashrc, ~/.zshrc):
sb() {
"$HOME/.cargo/bin/sb" "$@"
sb_last_path="${XDG_RUNTIME_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}}/sb/last_path"
if [ -f "$sb_last_path" ]
then
cd "$(cat "$sb_last_path")"
rm -i -f "$sb_last_path"
fi
}After adding the function, reload your shell configuration:
source ~/.bashrc # or source ~/.zshrcProject Structure
Current code layout is modular:
src/main.rs: app state, event loop, orchestration, and top-level workflowssrc/app_input.rs: input editing helperssrc/app_meta.rs: permissions/owner/group metadata helperssrc/app_render_cache.rs: entry render-cache generationsrc/app_search.rs: built-in search and path-filter matching helperssrc/app_files.rs: file-type classification helperssrc/app_sizes.rs: folder-size and aggregate-size scanning helperssrc/app_git.rs: Git status/background cache helperssrc/app_archive.rs: archive mount and preview lifecycle helperssrc/integration/: integration catalog, probing, rows, and install flowsrc/ui/: CLI output, icons, panels, search spans, and status renderingsrc/util/: shared formatting helpersCargo.toml: dependencies and release profile settings
Dependencies
From Cargo.toml:
ratatui(UI)crossterm(terminal events/raw mode)chrono(timestamps)devicons(file icons)hostname(header prompt)users(owner metadata)clap(present as dependency)regex(search regex mode)rayon(parallel entry render-cache build)unicode-width(display-width-aware list-mode alignment)











