Inside the Rule Engine: From Evidence to Alternatives

The Fuck's rule engine is the layer that turns a captured failure into competing repair candidates. This chapter explains the rule contract, how bundled and user-provided rules enter one pipeline, how output requirements and exceptions shape matching, and why priority is an ordering policy rather than a probability of correctness. The result is a practical way to judge both the engine's flexibility and the code-trust boundary created when rules run inside the same process as The Fuck.

A rule is a small decision module

A rule has a deliberately narrow public shape. It receives a Command containing the script and the output associated with it. Its match function answers whether the rule recognizes this command context. Its get_new_command function returns either one replacement string or several alternatives. The rule may also declare whether it is enabled by default, whether it has a side effect, what priority it should receive, and whether it requires output before it can match.

This contract separates recognition from construction. A matcher does not need to know how the user will select a result, update history, or invoke the shell. A command builder does not need to discover every other rule that might also apply. The engine can ask many independent modules the same question, then carry their answers forward as candidates. That separation is the reason the project can support very different failures—misspelled tools, Git diagnostics, permission errors, or missing files—without putting every exception into one giant conditional function.

The contract is small, but the input is not. The command's whole script preserves the form that can later be emitted or rerun. Its output carries the failed program's diagnostic, if the capture path succeeded. Its lazily computed parts let a rule inspect the program name, subcommand, and arguments. A rule can therefore match a relationship among command, output, and local context rather than searching the command string in isolation. When a rule declares that output is required and output is unavailable, the engine skips it before calling the matcher. Missing evidence changes the candidate set at the point where matching happens.

The Fuck searches three broad sources of rules. Bundled modules provide the project's built-in behavior. A user's rule directory allows local corrections for commands or workflows that the project cannot anticipate. Installed contribution packages can expose another collection of rules under the project's naming convention. All three sources are discovered through the same loading path and become the same kind of Rule object. The engine does not create a separate user experience for a local rule; it gives the rule the same opportunity to match and propose a result.

Discovery is filtered before matching. Excluded names are skipped, and a rule that is not enabled by default is not loaded into the active set unless the settings explicitly request it. The default configuration can enable the normal catalog as a whole, while a narrower rule list can select specific behavior. Priority overrides can also be supplied through settings. This allows the user to decide not only which repairs exist, but which repair families should be considered first.

The settings themselves come from multiple layers: a generated configuration file, environment variables, and command-line arguments.