project ❯ gti status
zsh: command not found: gti
project ❯ welp
welp git status ↵ run · esc nah
Why welp
thefuck is one of the most-loved command-line tools ever made. It has also had no release since January 2022, and it breaks on Python 3.12 and newer (No module named 'imp'). welp keeps what made it great and quietly fixes the rest.
| thefuck | welp | |
|---|---|---|
| Needs Python | yes | no, one small binary |
| Last release | January 2022 | active |
| Speed | starts Python every time | starts in about 3 ms, a typical fix in about 20 ms |
| Runs a failed command again to read its output | every command | never rm, mv, dd, editors, ssh and the like |
fuck --yeah |
yes | yes |
| Moves your setup over | welp migrate keeps your alias and settings |
|
| Your own rules | Python files | TOML files, no code needed |
| Rules | about 170 | 52 so far: the everyday git, file, package and typo fixes |
| Personality | the name | a shrug, three voices, welp stats |
| Shells | bash, zsh, fish, tcsh, PowerShell | bash, zsh, fish |
Speed measured on a MacBook Pro with welp fix; your numbers will vary. Rule names match thefuck's, so your exclude_rules keep working.
Meet the voice
welp is lowercase, low-key and a little dry. It shrugs when it has nothing, has a line for particular fixes, marks milestones and notices when you keep making the same typo:
project ❯ welp
welp git status
gti → git, 10 times now. we don't have to talk about it.
project ❯ welp
welp ¯\_(ツ)_/¯ nothing to fix here. that one's all you.
Pick a voice in your settings: chill (the default, a line now and then), spicy (teases you every time) or quiet (just the fix).
welp stats shows what it remembers:
project ❯ welp stats
welp your mistakes, lovingly kept
fixes 142 since oct 22, 2026
favorite rule git_push (38)
top typos gti → git (14) · sl → ls (5) · pyhton → python (3)
verdict you and git have a thing going on.
It keeps only counts, rule names and the mistyped words, never your commands, in ~/.local/state/welp/stats.toml. Set remember = false to turn it off.
Install
No Rust? Grab a prebuilt binary for macOS or Linux from the releases page, unpack it and put welp somewhere on your PATH. Homebrew is coming.
Set up
Add one line to your shell config, then open a new terminal:
| Shell | Line | File |
|---|---|---|
| zsh | eval "$(welp init zsh)" |
~/.zshrc |
| bash | eval "$(welp init bash)" |
~/.bashrc |
| fish | welp init fish | source |
~/.config/fish/config.fish |
Prefer another word? Add --alias, for example eval "$(welp init zsh --alias oops)".
Coming from thefuck
It comments out the thefuck lines in your shell config (with a backup next to each file), adds welp in their place with your alias, and turns ~/.config/thefuck/settings.py into ~/.config/welp/config.toml.
Rules
| Rule | What it fixes |
|---|---|
no_command |
A mistyped program name: gti → git |
git_not_command |
A mistyped git subcommand: git comit → git commit |
git_push |
Sets the upstream when a new branch has none |
git_pull |
Sets the tracking branch, then pulls |
git_checkout |
Creates the branch when it does not exist yet |
git_branch_delete |
-d → -D for a branch that is not merged |
git_commit_add |
Stages changed files when a commit has nothing staged |
git_add |
Stages a file git does not know yet, then runs the command again |
git_add_force |
Adds --force to stage a file your .gitignore covers |
git_branch_exists |
Recreates or switches to a branch that already exists (-d, never -D) |
git_clone_git_clone |
Drops the second git clone from a pasted command |
git_hook_bypass |
Adds --no-verify to skip hooks on am, commit or push |
git_main_master |
Swaps main and master when the branch is not there |
git_merge |
Merges the remote branch git suggests |
git_push_pull |
Pulls first when a push is rejected, then pushes |
git_rebase_no_changes |
git rebase --skip for a patch that came out empty |
git_remote_seturl_add |
set-url → add when the remote does not exist |
git_rm_local_modifications |
Adds --cached to keep a file with local changes |
git_rm_recursive |
Adds -r to remove a folder |
git_rm_staged |
Adds --cached to keep a file with staged changes |
git_stash |
Stashes your changes, then runs the command again |
did_you_mean |
Uses the fix a tool suggests: cargo, npm, pip, brew, gh and more |
sudo |
Runs the command again with sudo after "permission denied" |
chmod_x |
Makes a script executable before running it |
apt_get |
Installs a missing program the system names, then runs it |
cd_mkdir |
Creates the folder you tried to cd into |
cd_parent |
cd.. → cd .. |
mkdir_p |
Adds -p when parent folders are missing |
cp_omitting_directory |
Adds -r to copy a folder |
rm_dir |
Adds -r to remove a folder |
grep_recursive |
Adds -r to search a folder |
touch |
Creates missing folders, then the file |
sl_ls |
sl → ls |
cat_dir |
cat on a folder → ls |
cd_correction |
Fixes a misspelled folder in a cd path: cd Documnets → cd Documents |
has_exists_script |
Runs a script in this folder with ./ |
ln_no_hard_link |
Adds -s when a hard link to a folder is not allowed |
man_no_space |
mandiff → man diff |
missing_space_before_subcommand |
gitbranch → git branch |
quotation_marks |
Makes mismatched quotes match: 'text" → "text" |
sudo_command_from_user_path |
Keeps your PATH under sudo for a program only you can find |
unsudo |
Drops sudo from a command that refuses to run as root |
brew_link |
Previews what brew link --overwrite would replace |
brew_reinstall |
Reinstalls a formula that is already installed and up to date |
brew_uninstall |
Adds --force to remove every installed version |
go_run |
go run foo → go run foo.go |
java |
java Foo.java → java Foo |
javac |
javac Foo → javac Foo.java |
npm_run_script |
npm build → npm run-script build for a script in package.json |
pip_install |
Installs with --user (then sudo) after a permission error |
python_execute |
python foo → python foo.py |
yarn_command_not_found |
Fixes a mistyped yarn command |
welp rules lists them. More of thefuck's 170 rules are being ported. Pull requests are welcome.
Settings
~/.config/welp/config.toml (or $XDG_CONFIG_HOME/welp/config.toml):
= true # false runs the first fix straight away
= 3 # seconds to wait when reading a command's output
= 15
= ["lein", "react-native", "gradle", "./gradlew", "vagrant"]
= ["rm", "mv", "dd", "vim", "ssh"] # never run these twice (the full default list is longer)
= []
= "chill" # chill, spicy or quiet
= true # false stops welp stats from counting
Set NO_COLOR to drop the colours; welp keeps the words.
Your own rules
Teach welp a fix without writing code: drop a TOML file in ~/.config/welp/rules/.
# ~/.config/welp/rules/please.toml
= "please"
= "please → sudo"
= '^please (?P<rest>.+)$'
= "sudo {rest}"
A rule can check the program, a regex on the command (script) and a regex on what it printed (output). Its fix (or a list of fixes) can use {script} and any named group from those regexes. Your fixes are offered first; add first = false to offer them after welp's own. welp rules lists yours and says what's wrong with any file it can't read.
Adding a rule to welp
A rule is a name, a check and a fix, in src/rules/. Each comes with a test that feeds it a command and the output a real tool printed:
Rule ,
Run cargo test before opening a pull request.
The demo above is a real session: demo/record.sh sets up a throwaway repo and types the commands into zsh.
Support
If welp saves you some typing, you can buy me a coffee or come hang out on Discord.
Credits
welp's rules are ports of thefuck's, by Vladimir Iakovlev and its contributors (MIT). welp is not affiliated with thefuck.
License
MIT