# pay-respects: a Rust rewrite of the command-not-found fixer

> pay-respects is a Rust command line tool that suggests a correction when you mistype a shell command, with TOML rules parsed into Rust code, shell integration for bash, zsh, fish, nushell and PowerShell, and a pluggable module system. It suits a shell-heavy workflow, and its AGPL-3.0 licence is the first thing to check.

**iffse/pay-respects** — Command suggestions, command-not-found and thefuck replacement written in Rust

- Repository: https://github.com/iffse/pay-respects
- Website: https://codeberg.org/iff/pay-respects
- Stars: 730 · Forks: 36
- Language: Rust
- License: AGPL-3.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/iffse-pay-respects

## Press F and the shell proposes a fix

The premise is small and good. You mistype a command, the shell tells you the command was not found, and instead of typing the correction yourself you press a key and the shell proposes one.

The key is F, and the name comes from the phrase in the documentation: you can now press F to pay respects, with a link to the Wikipedia article of the same name.

The tool is written in Rust, and the repository description calls it a command suggestions, command-not-found and thefuck replacement. That last word is the important part of the positioning. thefuck was the well known tool that did this, and pay-respects is explicitly a replacement rather than an alternative, which sets expectations about the shape of the thing.

The feature list in the project documentation is specific about what it claims. Sub-millisecond performance under 1ms, with benchmarks referenced. Suggestions are verified before the user is prompted, and there are no sudo suggestions when you are using doas. The rules are written in TOML and parsed into Rust code, so you do not need to know Rust to add one, and raw Rust code can be used where TOML is not enough. Modules can be added in your favourite language. An AI module comes to the aid when no rule matches the error. And the core binary is under 1MB.

The homepage is on Codeberg, at codeberg.org/iff/pay-respects, and the licence is AGPL-3.0.

## Shell integration is the mechanism, and it differs per shell

pay-respects is not a program you run instead of your shell. It is a program your shell calls, and how you wire it up depends on which shell you are in. The documentation gives a section per shell.

For bash, zsh and fish, you append a line to your configuration file, and the --alias flag is no longer required as of version 0.7. The generated lines are:

```sh
> eval "$(pay-respects bash --alias)"
> eval "$(pay-respects zsh --alias)"
> pay-respects fish --alias | source
```

The --alias option takes a custom key and defaults to f. There is a second argument, --nocnf, which disables the command_not_found handler.

For nushell the output is added to the configuration file, either directly or saved to a file that the configuration then sources:

```sh
> pay-respects nu --alias [<alias>] | save -f ~/.pay-respects.nu
```

and the file is sourced from the configuration with source ~/.pay-respects.nu.

For PowerShell the output is appended to the profile, either by adding the line or by piping it there:

```pwsh
> pay-respects pwsh --alias [<alias>] >> $PROFILE
```

The alias argument has a bracket around it in the nushell and PowerShell examples, which is the documentation's way of showing that it is optional.

There is also a documented manual aliasing form, marked as removed after version 0.7, so if you are following an older tutorial that sets up an alias f by hand, that is the pre-0.7 style and the eval based line replaced it.

## Two environment variables are all a custom shell needs

If you use a shell the project does not ship a section for, the documentation explains the general contract. pay-respects only requires two environment variables to work: _PR_SHELL, the binary name of the current working shell, and _PR_LAST_COMMAND, the last command.

The general example is a one-liner:

```sh
> eval $(_PR_SHELL=sh _PR_LAST_COMMAND="git comit" pay-respects)
```

The tool echoes back, if applicable, commands that should be evaluated by the working shell, such as cd commands to change the directory. That is the second half of the design and it is worth understanding: pay-respects does not only propose a command, it can propose a command with a directory change attached, which is why the inline mode example can turn z payrespe into cd /home/iff/Code/pay-respects.

Three more variables are optional and exist to reduce unnecessary work rather than to enable the tool. _PR_ALIAS is a list of aliases to commands, separated by newlines with zsh-like formatting, for example gc=git commit. _PR_ERROR_MSG is the error message from the previous command, and pay-respects will capture output from multiplexers or rerun the previous command to get the error message if it is absent. _PR_EXECUTABLES is a space separated list of commands or executables, and the tool searches PATH if it is absent.

That last variable is the one to think about if the tool proposes a wrong fix. Without it, the tool has to search your PATH, which means it can suggest a command that exists but is not the one you meant.

## Modes, integration switches, and the inline experiment

The behaviour of the tool is selected with _PR_MODE, and the modes are worth knowing because they cover very different situations.

noconfirm executes suggestions without confirming. inline returns the best fix with no execution at all. echo prints suggestions to stdout without executing. cnf is the mode used for the command not found hook.

The inline mode is also available as a key binding, and the documentation calls it experimental: Ctrl+X gives on-the-fly correction with no execution, so gitcommit followed by C-X C-X becomes git commit.

There is a large set of switches for turning things off, and they are worth skimming because they show what the tool does behind the scenes. _PR_NO_CONFIG stops it loading configurations. _PR_NO_DESPERATE disables the desperate functions, which are slow but might give better results. _PR_PREFIX is a shell prefix before the command acting as an identifier, and it is required for multiplexer command log capturing. Then there is a family of integration disables: _PR_NO_ZOXIDE, and _PR_NO_MULTIPLEXER, which is equivalent to turning off _PR_NO_TMUX, _PR_NO_SCREEN, _PR_NO_ZELLIJ, _PR_NO_WEZTERM and _PR_NO_KITTY individually.

The integrations themselves are worth a paragraph. The multiplexer integration covers tmux, GNU Screen, Zellij, WezTerm and kitty, and captures the command log inside the session so that error messages do not need the command to be rerun. It requires an English locale, in practice LANG=C, because that output is what the matching uses, and it requires a prompt prefix before your command, which the initialization templates set automatically. The zoxide integration uses zoxide's database to navigate through directories.

## Rules as TOML, modules in any language, and an optional AI layer

The repository layout explains the architecture. The Cargo.toml defines a workspace with the core crate as the only default member, and two optional module crates, module-runtime-rules and module-request-ai. The default-members line is just core, which means a plain install is the small binary and the rest is opt-in.

The release profile is tuned for size: strip is on, codegen-units is 1 and lto is true, which is how a feature set this size stays under 1MB.

The rules live in the rules/ directory, with rules.md and modules.md documenting them, and the parser/ directory handles the TOML to Rust compilation step. The claim is that you do not need to know Rust to write a rule because the TOML is parsed into Rust code, and that raw Rust code can be used when TOML is not enough for a complex situation. A custom module can be written in another language entirely.

The AI module, module-request-ai, is the piece to look at closely. It is described as coming to the aid when there is no rule for the error, which means it makes a request to an AI service, and it is a separate crate for a reason: a tool that runs on every mistyped command should not make network calls by default.

The other top-level entries confirm the shape of the project. There is config.md for configuration, roadmap.md, a flowchart.mmd for the decision flow, man-src/ and man/ for the man pages with a Makefile target that renders them through pandoc, tests/ with a test.sh and a benchmark.sh, select/, utils/, core/ and a flake.nix for Nix builds, plus an init.fish and a pay-respects.plugin.zsh for the shell plugin setups.

## Installing, and what the package managers cover

The preferred route is a package manager, and the documentation lists them by distribution. The AUR build for Arch Linux is installed with paru -S pay-respects, with a -bin variant. Arch Linux CN has sudo pacman -S pay-respects, and it is also the ARM entry. On macOS and anything else, a Homebrew tap provides brew install timescam/homebrew-tap/pay-respects. On NixOS, nix-env -iA nixos.pay-respects. A Repology badge tracks which distributions carry the package.

If no package manager has it, the alternative is a pre-built binary from the GitHub releases, with install scripts for both platforms. For Unix:

```sh
curl -sSfL https://raw.githubusercontent.com/iffse/pay-respects/main/install.sh | sh
```

and for Windows there is a PowerShell script, install.ps1 in the repository, with the command given in the documentation as irm against a raw GitHub URL.

Building from source is the third option, and the Makefile shows how small the surface is. The install target runs cargo install --path core, and install-all adds the two module crates:

```make
install-all:
	echo "Installing pay-respects core and all modules."
	cargo install --path core
	cargo install --path module-runtime-rules
	cargo install --path module-request-ai
```

The test target chains the Rust test suite and the suggestion tests, where the suggestion tests are a shell script in tests/ that checks the actual suggestions, and the bench target runs a benchmark.sh after a release build. The man target renders the man pages from the markdown sources through pandoc.

The project also ships a flake.nix with a flake.lock for Nix, and a Cross.toml for cross compilation, and the continuous integration runs on Woodpecker, which is the .woodpecker/ directory at the top of the tree.

## Where pay-respects is the wrong tool

The first limit is the licence. AGPL-3.0 is a strong copyleft, and for a personal shell tool that is not a concern. For a company that wants to ship pay-respects inside a product, or to modify it and serve the result over a network, the obligations are the ones you would expect from the AGPL. That is a licensing review, not a technical objection, but it is the first thing to check.

The second limit is that it does nothing for a shell you have not wired up. The value of the tool is entirely in the integration, and the integration is a line in your shell configuration. A user who declines to put a line in their .bashrc gets a binary that does nothing useful on its own.

The third is the accuracy ceiling. The tool is a rule matcher with a verification step, and its suggestions are only as good as the rule set. The documentation is candid that the AI module exists for the cases with no rule, which is a statement that the rules do not cover everything. A tool that guesses wrong on a command with side effects is worse than one that stays quiet, and the mitigation is the verification the tool does before prompting, not a guarantee.

The fourth is the environment coupling. The multiplexer integration needs an English locale, because the log matching uses that output, and it needs a prompt prefix. On a system with a non-English locale, or a customised prompt, the integration silently does less than the documentation implies. The zoxide integration similarly depends on zoxide's database being present.

The fifth is scope. pay-respects is about mistyped commands and command-not-found. It does not generalise into a shell assistant that understands what you are trying to do, and the inline mode, which comes closest to that, is labelled experimental in the documentation.

## Conclusion

pay-respects is worth trying if you mistype commands often enough to be annoyed by it, because the suggestions are verified before you are prompted, the rules are TOML files that do not require Rust to extend, and the binary is small enough that the install is not a decision. It is the wrong tool if you need a guaranteed no-install path, because the shell integration is what makes it work and that means a line in your shell configuration, and it is the wrong tool for a team that cannot accept AGPL-3.0. Before you wire it into a shell, check the three things the documentation puts in front of you: that you know which shell you are in, since the tool takes the shell name as an argument and the generated alias differs per shell; that the multiplexer integration, which covers tmux, GNU Screen, Zellij, WezTerm and kitty, needs an English locale because LANG=C is what the log matching uses; and that the AI module is a separate optional crate, since the core is the part that works without a network call.

## FAQ

### How do I install and set up pay-respects in my shell?

Append the generated line to your shell configuration, for example eval "$(pay-respects bash --alias)" for bash, pay-respects fish --alias | source for fish, and the equivalent for zsh, nushell or PowerShell. Packages exist for Arch Linux through the AUR, for macOS through a Homebrew tap, and for NixOS, and pre-built binaries can be fetched with an install script.

### What are _PR_SHELL and _PR_LAST_COMMAND used for?

They are the only two environment variables pay-respects requires, and they are what you set when you wire it into a shell it has no built-in section for. _PR_SHELL is the binary name of the current working shell and _PR_LAST_COMMAND is the last command, as in eval $(_PR_SHELL=sh _PR_LAST_COMMAND="git comit" pay-respects).

### How do I write my own rules for pay-respects?

The rules are written in TOML and parsed into Rust code, so you do not need to know Rust to add one, and raw Rust code can be used when TOML is not enough. The rules live in the rules/ directory, and additional sources can be added as modules written in another language, with the optional module crates module-runtime-rules and module-request-ai built separately from the core.

## Sources

- [iffse/pay-respects on GitHub](https://github.com/iffse/pay-respects)
- [License: AGPL-3.0](https://github.com/iffse/pay-respects/blob/main/LICENSE)
- [Project website](https://codeberg.org/iff/pay-respects)
- [README](https://github.com/iffse/pay-respects/blob/main/README.md)
- [Releases](https://github.com/iffse/pay-respects/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/iffse-pay-respects
