A feature-rich, POSIX-compliant shell profile that works on (almost) all shells. Designed for *NIX systems from desktops to embedded SBCs (tested on Ubuntu 25.04, Onion Omega2+ with BusyBox and MacOS Ventura).
No external dependencies required. Everything works out of the box.
- Syntax Highlighting - Real-time command highlighting as you type
- 7 Themes - Dracula, Nord, Gruvbox, Catppuccin, Tokyo Night, Monokai, Solarized
- Custom Neofetch - System info with theme-matched ASCII art
- Fuzzy CD - Jump to directories with partial names (
cdf partial) - Autojump - Learns your habits,
j partialjumps to frequently visited dirs - Smart CDPATH - Tab-complete from all CDPATH directories
- Directory Stack -
dshows numbered recent directories,cd -Njumps to them
- Shared History - Commands sync across all terminal sessions instantly
- Auto-suggestions - Fish-style prefix matching from history (shows in dim text)
- History Search - Press
Ctrl+Rand type to filter - History Stats -
histshows your most used commands
- Git Prompt - Shows branch, dirty state, stash count in your prompt
- Git Aliases - Shortcuts for common commands (
gst,gco,gl, etc.) - Works offline - No git required, gracefully degrades
- Custom Completion System - Built-in bash completion (no package needed)
- Smart Completions - For git, ssh, scp, kill, cd, make, and package managers
- Lazy Loading - Completions load on demand
- Global Aliases -
Gfor grep,Lfor less,Hfor head,Tfor tail - Spelling Correction -
cdspellauto-fixes cd typos - Vi Mode - Press
jjto exit insert mode - Plugin System - Drop scripts in
~/.profile.d/for easy organization
# Clone the repo
git clone https://github.com/efwxx/trinity.git ~/.dotfiles
# Link the profile
ln -sf ~/.dotfiles/profile ~/.profile
# Source it
source ~/.profile# Backup your existing profile
cp ~/.profile ~/.profile.bak
# Copy this repo's profile to your home
cp profile ~/.profile
# Start a new shell or source it
source ~/.profileecho '[[ -f ~/.profile ]] && . ~/.profile' >> ~/.bashrctheme # Show current theme
theme nord # Switch to Nord
theme gruvbox # Switch to Gruvbox
and so on...dracula- Purple/pink (default)nord- Arctic blue/whitegruvbox- Retro brown/greenmocha- Dark mocha catppuccin variantmacchiato- Medium macchiato catppuccin variantfrappe- Frappe catppuccin variantlatte- Light latte catppuccin varianttokyo- Tokyo Nightmonokai- Classic Monokaisolarized- Solarized light/dark
Some features can be toggled:
# Disable real-time syntax highlighting
unset RTSH_ENABLE
# Disable git prompt integration
unset GIT_PROMPT_ENABLEThis profile has a modular plugin system. Plugins are shell scripts that get loaded automatically on shell startup.
Plugins are loaded from these directories in order:
~/.profile.d/~/.dotfiles/.profile.d/
The plugin loader (60-plugin-loader.sh) does the following:
- Scans for
.profile.d/directories - Loads all
*.shfiles in each directory - Files are loaded in alphabetical order (hence the
10-,20-, etc. prefixes)
Create a new file in ~/.profile.d/ or ~/.dotfiles/.profile.d/:
# ~/.profile.d/90-my-plugin.sh
# Give it a descriptive name
# Variables and functions defined here are available in your shell
# You can use all theme colors
echo "My plugin loaded! Theme is: $SHELL_THEME"
# Define functions
my_custom_function() {
echo "Hello from my plugin!"
}
# Set aliases
alias myalias='echo "Custom alias"'
# Export variables
export MY_CUSTOM_VAR="value"The numbers at the start of plugin names control load order:
| Prefix | Purpose |
|---|---|
10- |
Core settings (PATH, history config) |
20- |
Navigation features |
30- |
History features |
40- |
Git integration |
50- |
Completions |
60- |
Plugin loader itself |
90- |
User custom plugins |
| Plugin | Lines | Description |
|---|---|---|
10-base.sh |
26 | History settings, PATH, EDITOR |
20-navigation.sh |
118 | Fuzzy cd, autojump, directory stack |
30-history.sh |
105 | Shared history, autosuggestions |
40-git.sh |
112 | Git aliases, git prompt |
50-completions.sh |
62 | Completion system |
60-plugin-loader.sh |
52 | Plugin loader + helper functions |
When plugins are loaded, these functions become available:
# List loaded plugins
plugin_list
# Reload all plugins
plugin_reloadTo temporarily disable a plugin, rename it:
mv ~/.profile.d/40-git.sh ~/.profile.d/40-git.sh.disabledOr move custom plugins to a separate directory:
mkdir ~/.my-plugins/
mv ~/.profile.d/my-custom.sh ~/.my-plugins/
# Then manually load: . ~/.my-plugins/my-custom.shFor plugins that work on both bash and ash:
# Good: Check for bash before using bash-specific features
if [ -n "$BASH_VERSION" ]; then
# Bash-only code here
set -o vi
fi
# Good: Use POSIX-compatible syntax
[ -z "$var" ] && echo "empty"
[ -n "$var" ] && echo "not empty"
# Avoid:
# - [[ ]] (bash-only)
# - (( )) (bash arithmetic)
# - function keyword (deprecated, but portable)
# - Process substitution <() (bash-only)Want to share a plugin? Drop it in ~/.profile.d/ with a descriptive name and it will be loaded on next shell start.
Completions are stored in .profile_completions/ and provide tab-completion for various commands.
50-completions.shsets up the completion system- Completion functions in
.profile_completions/*.shdefine completion rules - When you press Tab, bash uses these rules
| Completion | What it completes |
|---|---|
git.sh |
Branches, remotes, subcommands |
ssh.sh |
Hosts from ~/.ssh/config |
scp.sh |
Remote file paths |
kill.sh |
Process names and signals |
cd.sh |
Directories from CDPATH |
make.sh |
Targets from Makefile |
pkg.sh |
Packages for apt/yum/pacman/etc |
# ~/.profile_completions/mycmd.sh
_complete_mycmd() {
local cur="${COMP_WORDS[COMP_CWORD]}"
# Complete with these words
COMPREPLY=($(compgen -W "start stop restart status" -- "$cur"))
}
# Register the completion
complete -F _complete_mycmd mycmdInside a completion function:
${COMP_WORDS[@]}- Array of words on the command line${COMP_CWORD}- Index of current word being completed${COMP_LINE}- Full command lineCOMPREPLY- Array of completions to offer
~/.dotfiles/
├── profile # Main profile
├── README.md # This file
├── .github/
│ └── ISSUE_TEMPLATE/
│ ├── bug_report.md # Bug report template
│ └── feature_request.md # Feature request template
├── .profile.d/ # Built-in plugins
│ ├── 10-base.sh
│ ├── 20-navigation.sh
│ ├── 30-history.sh
│ ├── 40-git.sh
│ ├── 50-completions.sh
│ └── 60-plugin-loader.sh
└── .profile_completions/ # Completion modules
├── git.sh
├── ssh.sh
├── scp.sh
├── kill.sh
├── cd.sh
├── make.sh
└── pkg.sh
These files are created automatically:
| File | Purpose |
|---|---|
~/.sh_history |
Shared command history |
~/.cdhistory |
Directory visit tracking for autojump |
- bash or ash
- grep, sed, awk
- find, cut, tr
git
fzf
zoxide
Everything else is optional and will be auto-detected.
cdf foo # Fuzzy find and cd into directory containing "foo"
j bar # Jump to most visited directory matching "bar"
d # Show directory stack
cd -2 # Go to 2nd directory in stack
.. # cd .. (already exists)
... # cd ../.. (already exists)ps aux G nginx # Pipe to grep
cat file L # Pipe to less
ls H # Pipe to head# Type a command prefix, press Ctrl+R repeatedly to cycle matches
# Or use the autosuggestion (shown dimmed, press right arrow to accept)
hist # Show history statistics
hist 20 # Show top 20 commandsgst # git status -sb
gco main # git checkout main
gcb newbranch # git checkout -b newbranch
gl # git log with graph
gp # git push
ga # git add
gc "message" # git commit -m "message"Tested and working on:
- Ubuntu / Debian
- Arch Linux
- Void Linux
- macOS
- OpenWRT (ash)
- Alpine Linux
- Android (Termux)
- MacOS Ventura (13.7.8)
Found a bug? Want a feature? Open an issue or PR.
- Fork it
- Create your feature branch
- Make your changes
- Test on a minimal system (like OpenWRT)
- Submit a PR
MIT - Do whatever you want with it.
Built from scratch with love. Shell scripting is underrated.