How thefuck Determines Rule Priority: A Deep Dive into Command Correction Ordering
thefuck uses a three-layer priority system—rule-defined constants, user configuration overrides, and a default value of 1000—to determine the evaluation order of correction rules and rank multiple suggested fixes.
Understanding how thefuck rule priority works is essential for customizing the command-line tool's behavior. In the nvbn/thefuck repository, every correction rule receives a numeric priority that controls both which rules are tested first and how their suggested fixes are ranked when multiple corrections apply to the same mistyped command.
Understanding thefuck Rule Priority Sources
The priority system combines values from three distinct sources, applied in a specific precedence order.
Rule-Defined Priority in Module Files
Individual rules can declare their own priority by setting a module-level variable named priority. This value is typically defined at the top of the rule file in thefuck/rules/.
# thefuck/rules/long_form_help.py
priority = 5000
When the rule loader processes this file, it extracts this constant using getattr(rule_module, 'priority', DEFAULT_PRIORITY).
User Configuration via Environment Variables
Users can override any rule's priority without modifying source code by setting the THEFUCK_PRIORITY environment variable. This variable accepts a colon-separated list of RULE=NUM pairs.
export THEFUCK_PRIORITY="git_pull=9000:cd=2000"
The configuration parser in thefuck/conf.py processes this string in the _priority_from_env method, splitting on colons and equals signs to build a priority dictionary.
The Default Priority Fallback
When a rule lacks an explicit priority variable and no user override exists, the system falls back to the constant defined in thefuck/const.py.
# thefuck/const.py
DEFAULT_PRIORITY = 1000
This ensures every rule has a deterministic priority value for sorting purposes.
How Priority Values Are Loaded and Applied
The rule loading pipeline combines these three sources into a final priority value for each enabled rule.
Extracting Priority in Rule.from_path
The Rule.from_path class method in thefuck/types.py orchestrates the priority resolution. It first attempts to read the module-level priority attribute, then checks for user-defined overrides in the settings object.
# thefuck/types.py (excerpt)
priority = getattr(rule_module, 'priority', DEFAULT_PRIORITY)
return cls(
name, rule_module.match, rule_module.get_new_command,
getattr(rule_module, 'enabled_by_default', True),
getattr(rule_module, 'side_effect', None),
settings.priority.get(name, priority), # User override applied here
getattr(rule_module, 'requires_output', True))
Parsing THEFUCK_PRIORITY Environment Variable
The settings initialization calls _priority_from_env to transform the environment string into a usable dictionary mapping rule names to integer priorities.
# thefuck/conf.py
def _priority_from_env(self, val):
for part in val.split(':'):
try:
rule, priority = part.split('=')
yield rule, int(priority)
This dictionary is stored in settings.priority and consulted during rule instantiation.
Sorting and Ordering Corrected Commands
Priority influences the system at two distinct stages: rule evaluation order and final command ranking.
Rule Evaluation Order
When the corrector initializes, it loads all enabled rules and sorts them by their resolved priority values. Higher priority rules are placed earlier in the list, ensuring they are evaluated first when matching against a failed command.
# thefuck/corrector.py
paths = [...]
return sorted(get_loaded_rules(paths), key=lambda rule: rule.priority)
This sorting occurs in corrector.get_rules, producing a deterministic evaluation sequence.
Calculating Command Priority for Multiple Fixes
When a rule generates multiple corrected command suggestions, each receives a calculated priority based on its position in the suggestion list. The get_corrected_commands method in thefuck/types.py multiplies the rule's base priority by the one-based index of the suggestion.
# thefuck/types.py (inside Rule.get_corrected_commands)
for n, new_command in enumerate(new_commands):
yield CorrectedCommand(
script=new_command,
side_effect=self.side_effect,
priority=(n + 1) * self.priority)
This ensures that the first suggestion from a high-priority rule ranks above subsequent suggestions from the same rule, and above all suggestions from lower-priority rules.
Final Deduplication and Sorting
After collecting all corrected commands from all matching rules, the corrector organizes them into the final output list. The organize_commands function deduplicates entries while preserving the highest priority instance of each unique command, then sorts the result by the calculated priority values.
# thefuck/corrector.py
without_duplicates = {
command for command in sorted(
corrected_commands, key=lambda command: command.priority)
if command != first_command}
sorted_commands = sorted(without_duplicates,
key=lambda corrected_command: corrected_command.priority)
This produces the final ordered list of suggestions presented to the user.
Summary
- Three-layer priority system: Rule modules define base values, users override via
THEFUCK_PRIORITYenvironment variable, andDEFAULT_PRIORITY(1000) serves as the fallback. - Loading process:
Rule.from_pathinthefuck/types.pyextracts module priorities and applies user settings overrides during rule instantiation. - Evaluation order:
corrector.get_rulessorts enabled rules by priority, ensuring higher values are tested first. - Command ranking: When rules produce multiple fixes, each command receives a calculated priority of
(position + 1) * rule.priority, then gets deduplicated and sorted incorrector.organize_commands.
Frequently Asked Questions
What is the default priority value in thefuck?
The default priority value is 1000, defined as DEFAULT_PRIORITY in thefuck/const.py. This value is assigned to any rule that does not explicitly declare a priority variable in its module file and has no user-defined override.
How can I override a specific rule's priority without modifying source code?
Set the THEFUCK_PRIORITY environment variable with a colon-separated list of RULE=NUM pairs. For example, export THEFUCK_PRIORITY="git_pull=9000:cd=2000" assigns priority 9000 to the git_pull rule and 2000 to the cd rule. The Settings._priority_from_env method in thefuck/conf.py parses this string during initialization.
Why does thefuck multiply priority by position when generating multiple fixes?
When a rule generates multiple corrected commands, the system calculates each command's final priority as (n + 1) * rule.priority where n is the zero-based index of the suggestion. This ensures that the first suggestion from a high-priority rule ranks higher than subsequent suggestions from that same rule, while maintaining the relative ordering between different rules. The logic is implemented in Rule.get_corrected_commands within thefuck/types.py.
Which file should I edit to change a rule's priority permanently?
To change a rule's priority permanently for all users of that rule, edit the specific rule file in thefuck/rules/ and add or modify the module-level priority variable. For example, setting priority = 5000 at the top of thefuck/rules/long_form_help.py ensures that rule always loads with priority 5000 unless overridden by user configuration.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →