Skip to content

Latest commit

 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

oops

Fix your last failed shell command.

oops silently watches every command you run. When one fails, type oops and it suggests — or automatically applies — a corrected version. The failed command is never re-executed; oops analyzes the command string, exit code, and context (git state, filesystem, shell history) to produce a fix.

$ gti status
zsh: command not found: gti

$ oops
git status
On branch main...

Installation

From source

go install github.com/pxgray/oops/cmd/oops@latest

Or clone and build:

git clone https://github.com/pxgray/oops
cd oops
go build -o bin/oops ./cmd/oops   # build to ./bin/oops
# or
go install ./cmd/oops             # install to $GOPATH/bin

Requires Go 1.25+. The binary has no runtime dependencies.

Shell integration

After installing the binary, add the hook to your shell's config file. The hook tracks each command passively — it never re-runs anything.

zsh

Add to ~/.zshrc:

eval "$(oops --alias zsh)"

bash

Add to ~/.bashrc:

eval "$(oops --alias bash)"

fish

Add to ~/.config/fish/config.fish:

oops --alias fish | source

Restart your shell (or source the config file) to activate. You can now type oops after any failed command.

Usage

Just type oops after a failed command:

$ cd nonexistent-dir
bash: cd: nonexistent-dir: No such file or directory

$ oops
mkdir -p nonexistent-dir && cd nonexistent-dir

When multiple fixes are possible, an interactive picker appears (requires a TTY). Use arrow keys to select and Enter to confirm. Press q or Ctrl+C to cancel without running anything.

What it fixes

Situation Example Fix
Typo in command name gti status git status
Permission denied cat /etc/shadow sudo cat /etc/shadow
cd to nonexistent dir cd myproject mkdir -p myproject && cd myproject
Wrong git branch name git checkout mian git checkout main
Push without upstream git push (no upstream) git push --set-upstream origin <branch>
Nothing staged to commit git commit -m "..." git commit --amend -m "..."
Python venv not activated python script.py (venv present) source venv/bin/activate && python script.py
Repeated history prefix docker run ... (partial match) best matching prior command

Commands

oops               # print help
oops --alias SHELL # print shell integration hook (bash/zsh/fish)
oops run           # analyze and fix last command (called by the hook)
oops rules         # list all rules and their enabled/disabled status
oops config        # show config file path and current settings

Configuration

Config file: ~/.config/oops/config.toml (created on first use if needed; missing file uses defaults silently).

[core]
timeout     = "5s"    # max time for rule evaluation
cache_max_age = "1h"

[predictor]
history_limit   = 10000  # how many history entries to load
max_suggestions = 5      # max candidates shown in picker

[ui]
interactive = true  # show TUI picker when multiple fixes exist
color       = true

[rules]
disabled = []       # list rule names to disable, e.g. ["history_repeat"]

Disabling rules

[rules]
disabled = ["history_repeat", "python_venv"]

Available rule names: command_not_found, git_branch, git_push_upstream, git_commit_amend, cd_mkdir, python_venv, typo_flag, history_repeat.

Run oops rules to see all rules and their current status.

How it works

oops uses a priority-ordered rule pipeline:

  1. The shell hook captures the command string and exit code after each prompt.
  2. On oops, the hook passes OOPS_CMD, OOPS_EXIT, OOPS_CWD, and OOPS_SHELL to oops run.
  3. Rules are evaluated in priority order; each rule inspects the command and optionally performs secondary checks (git state, filesystem presence, etc.).
  4. Candidates are ranked by confidence. The highest-confidence fix is applied automatically, or presented in the interactive picker.
  5. The chosen command is written to stdout; the shell hook evals it. All UI output goes to /dev/tty.

Command typo correction uses a BK-tree with Damerau-Levenshtein distance (transpositions cost 1) combined with Jaro-Winkler fuzzy scoring, so single-character transpositions like gti → git are reliably caught.

Development

task build    # build to bin/oops
task test     # run all tests
task install  # install to $GOPATH/bin
task clean    # remove bin/

Run a single test:

go test ./internal/rules/ -run TestCdMkdir -v

About

A CLI tool written in Go that hooks into bash, zsh, and fish to detect failed commands and suggest corrections using BK-tree fuzzy matching, radix tree lookups, and shell-specific rules.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages