How Bundled Rules Are Distinguished from User-Defined Rules in TheFuck
Bundled rules are distinguished from user-defined rules by their file system origin: bundled rules reside in the package's internal thefuck/rules/ directory, while user-defined rules are loaded from the user's configuration directory at ~/.config/thefuck/rules/.
TheFuck is a command-line correction tool that suggests fixes for mistyped console commands. It supports three types of rules: bundled (built-in) rules shipped with the package, user-defined rules created locally, and third-party contributed rules from external packages. Understanding how the system distinguishes between bundled and user-defined rules is essential for customizing behavior without modifying core library files.
How TheFuck Loads Rules from Different Sources
The rule loading mechanism in thefuck/corrector.py treats each source differently based on its physical location on the filesystem.
Bundled Rules Location
Bundled rules are stored in the rules/ subdirectory inside the installed package. The system identifies these by resolving the path relative to thefuck/corrector.py itself:
# thefuck/corrector.py
yield Path(__file__).parent.joinpath('rules')
This path points to the directory containing the library's source code, making it clear these are built-in rules distributed with the package.
User-Defined Rules Location
User-defined rules are identified by their location in the user's configuration directory. The system creates and checks ~/.config/thefuck/rules/ (or $XDG_CONFIG_HOME/thefuck/rules/):
# thefuck/corrector.py
yield settings.user_dir.joinpath('rules')
Because this path originates from settings.user_dir rather than the package directory, the system implicitly distinguishes these as user-created extensions.
Third-Party Contributed Rules
While not part of the bundled vs. user distinction, the system also scans for external packages named thefuck_contrib_* on sys.path, loading their rules subdirectories after processing bundled and user rules.
Code Implementation: Path Resolution in corrector.py
The get_rules_import_paths() function in thefuck/corrector.py (lines 28-38) generates the ordered list of directories to scan for rule files:
# thefuck/corrector.py
def get_rules_import_paths():
# Bundled rules: package directory
yield Path(__file__).parent.joinpath('rules')
# User-defined rules: config directory
yield settings.user_dir.joinpath('rules')
# Third-party packages:
for path in sys.path:
for contrib_module in Path(path).glob('thefuck_contrib_*'):
contrib_rules = contrib_module.joinpath('rules')
if contrib_rules.is_dir():
yield contrib_rules
The distinction is purely path-based: bundled rules come from the package installation directory, while user rules come from the configuration directory returned by settings.user_dir.
User Configuration Directory Setup
The system ensures the user rules directory exists through the _setup_user_dir() method in thefuck/conf.py (lines 68-75):
# thefuck/conf.py
def _setup_user_dir(self):
"""Returns user config dir, create it when it doesn't exist."""
user_dir = self._get_user_dir_path()
rules_dir = user_dir.joinpath('rules')
if not rules_dir.is_dir():
rules_dir.mkdir(parents=True)
self.user_dir = user_dir
This creates ~/.config/thefuck/rules/ on first run, establishing the location where user-defined rules will be loaded from.
Practical Examples
Creating a User-Defined Rule
Place a Python file in ~/.config/thefuck/rules/ to create a custom rule that the system will distinguish from bundled rules:
# ~/.config/thefuck/rules/hello_world.py
priority = 100 # optional, higher runs earlier
def match(command):
# Trigger when the user types `hello`
return command.script == 'hello'
def get_new_command(command):
# Suggest the corrected command
return 'echo "Hello, World!"'
Because this file resides in the user configuration directory, get_rules_import_paths() yields it separately from the bundled rules in the package directory.
Disabling a Bundled Rule
You can disable specific bundled rules by adding them to the exclusion list in ~/.config/thefuck/settings.py:
# ~/.config/thefuck/settings.py
exclude_rules = ['git_push'] # disables the bundled `git_push` rule
The Rule.from_path() method in thefuck/types.py (lines 37-40) checks this exclusion list before loading:
# thefuck/types.py
if name in settings.exclude_rules:
logs.debug(u'Ignoring excluded rule: {}'.format(name))
return
This mechanism works uniformly for both bundled and user-defined rules, though it is most commonly used to suppress specific bundled behaviors.
Summary
- Path-based distinction: Bundled rules reside in
thefuck/rules/inside the package installation, while user-defined rules live in~/.config/thefuck/rules/. - Loading order: The
get_rules_import_paths()function inthefuck/corrector.pyyields bundled paths first, then user paths, then third-party contributions. - Unified interface: Both rule types implement the same
match()andget_new_command()interface and are loaded by the sameRule.from_path()mechanism. - Configuration control: Users can disable any rule (bundled or custom) via
exclude_rulesinsettings.py, regardless of its origin.
Frequently Asked Questions
How does TheFuck know which rules are built-in versus custom?
TheFuck distinguishes bundled from user-defined rules by their file system location. Bundled rules are loaded from the package's internal thefuck/rules/ directory (resolved via Path(__file__).parent.joinpath('rules')), while user-defined rules are loaded from ~/.config/thefuck/rules/ (resolved via settings.user_dir.joinpath('rules')).
Can I override a bundled rule with my own version?
Yes. If you create a user-defined rule with the same filename as a bundled rule (e.g., git_push.py) in your ~/.config/thefuck/rules/ directory, both rules will be loaded. TheFuck merges all rules into a single list ordered by priority, so your custom rule can take precedence by setting a higher priority value in the module.
Where should I place my custom rules to ensure TheFuck finds them?
Place your custom rule files (Python modules ending in .py) in the rules subdirectory of your TheFuck configuration directory, typically located at ~/.config/thefuck/rules/ on Linux/macOS or %APPDATA%\thefuck\rules\ on Windows. The get_rules_import_paths() function automatically yields this path when scanning for available rules.
Do bundled and user-defined rules use the same programming interface?
Yes. Both bundled and user-defined rules implement the same interface: they must define a match(command) function that returns True when the rule should apply, and a get_new_command(command) function that returns the corrected command string. Both can optionally define a priority integer to control execution order, and both are loaded through the same Rule.from_path() mechanism in thefuck/types.py.
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 →