rFortune is a modern, cross-platform reimplementation of the classic Unix fortune program, written in Rust.
It displays a random quote or witty phrase from a plain text file, making it perfect for terminal startup messages, scripting, or just a bit of inspiration.
β¨ New in v0.5.5
π Multiple fortune file support
- Added support for multiple fortune files via the repeatable option
--file <PATH>.
Example: - Introduced the new configuration key
fortune_files(list). When defined, it takes priority overdefault_file. - Automatic config migration: if
fortune_filesis missing or empty, it is initialized automatically with the previousdefault_filevalue. - Unified JSON-based cache shared across all configured fortune files.
- Intelligent no-repeat mechanism: rFortune now avoids showing the same quote twice in a row from the same file.
π Cache robustness improvements
- Cache writes to the shared JSON store are now atomic: data is written to a temporary file and then replaced via rename to avoid partial/corrupted writes.
- Advisory file locking (via the
fs2crate) is used to protect concurrent access to the shared cache (last_quotes.json). This reduces races when multiple rFortune processes run simultaneously. - Windows fallback: on platforms with older rename semantics the implementation attempts a remove+rename fallback to ensure the store is replaced reliably.
- Internal cleanup: introduced a small
open_and_lock()helper to centralize file opening/locking logic and switched internal cache APIs to useanyhowfor richer error context. - Added an integration test (
tests/cache_tests.rs) and the dependenciesfs2andanyhow.
π§ Improved cross-platform behavior
- Fixed an issue with the
app_dir()function on Linux and macOS wheredirs::data_dir()could returnNonein CI or headless environments. - Added reliable fallbacks ensuring consistent paths:
- macOS β
$HOME/Library/Application Support/rfortune - Linux β
$HOME/.local/share/rfortune
- macOS β
- Fixed inconsistent cache path resolution caused by incorrect
app_dir()usage on Linux/macOS. - Introduced the new helper function
ensure_cache_dir()to centralize cache directory creation, improving reliability acrosssave_last_cache()andsave_last_cache_json(). - Ensures predictable configuration and cache directory behavior across all systems, including GitHub Actions.
βοΈ Deprecated
- The old
files_fortunekey and single-fileprint_random()function have been removed or replaced by the new multi-file logic.
π Features
- β Cross-platform: works on Linux, Windows, macOS Intel and Apple Silicon
- β‘ Fast and lightweight (native Rust binary)
- π Simple input format: one or more lines per fortune, separated by
% - πΉ UTF-8 support for multilingual content
- π§© Easily extensible
- π§ Built-in cache system to avoid showing the same fortune twice in a row
- β¨ New CLI with subcommands for config, file initialization and cache management
π¦ Installation
π§ AUR (Arch Linux)
# or
πΊ Homebrew (macOS/Linux)
π¦ Crates.io (Rust)
π₯ Download
Precompiled binaries are available in the Releases section.
| Platform | Architecture | File |
|---|---|---|
| Windows | x86_64 | rfortune-<version>-x86_64-pc-windows-msvc.zip |
| Linux | x86_64 | rfortune-<version>-unknown-linux-gnu.tar.gz |
| macOS Intel Architecture | x86_64 | rfortune-<version>-x86_64-apple-darwin.tar.gz |
| macOS Apple Silicon | aarch64 | rfortune-<version>-aarch64-apple-darwin.tar.gz |
π GPG Signature
All release archives are cryptographically signed with GPG.
.sigfiles contain the ASCII-armored detached signature for the corresponding archive.- You can verify the archive with:
π Public Key
The releases are signed with the following GPG key:
- Key ID: 423FABCE0A1921FB
- Fingerprint: 8118 9716 9512 2A32 1F3D C04C 423F ABCE 0A19 21FB
- Download: https://github.com/umpire274.gpg
To import the key from a keyserver:
Or from OpenPGP server:
Then verify the fingerprint:
π Usage
Running rfortune without subcommands prints a random fortune from the default file (rfortune.dat).
βοΈ First-time setup
When rfortune is launched for the first time and no configuration directory exists,
the application will ask whether to initialize its environment (creating the default
configuration and fortune files).
In non-interactive contexts, initialization happens automatically.
π§© Options & Subcommands
| Command / Option | Description |
|---|---|
-f, --file <PATH> |
Use a custom fortune file instead of the default |
config init |
Create the configuration file with default options |
config edit [--editor <E>] |
Open the configuration file in the systemβs default or a specified editor |
file init |
Create a sample default fortune file (rfortune.dat) |
cache clear |
Remove all cached last-used fortunes |
-V, --version |
Show version information |
-h, --help |
Show help message |
π‘ Examples
# Print a random fortune from the default file (rfortune.dat)
# Print a random fortune from a specific file
# Create the default configuration file in the user data directory
# Open the configuration file in the systemβs default text editor
# Open the configuration file with a specific editor (e.g. vi, nano, code)
# Create a sample default fortune file (rfortune.dat)
# Clear all cached last-used fortunes
Configuration (rfortune.conf)
Example:
default_file: "/home/user/.local/share/rfortune/rfortune.dat"
print_title: true
use_cache: true
# Optional: load additional quote files
fortune_files:
- "/usr/local/share/rfortune/philosophy.fort"
- "/usr/local/share/rfortune/tech.fort"
Priority order:
--file <PATH>CLI argument(s)fortune_fileslist in configdefault_file
Multiple Sources Configuration
You can load quotes from multiple files and rfortune will automatically choose one at random:
Or configure them permanently:
fortune_files:
- "/path/to/my_quotes.fort"
- "/path/to/jokes.fort"
If both are present, CLI always wins.
Smart Quote Repetition Avoidance
rfortune keeps a small cache and automatically avoids repeating the same quote twice in a row, but only for quotes from the same file.
This keeps the output natural across multiple sources.
Migration from older versions
If your previous configuration did not contain fortune_files,
rfortune will automatically migrate your config by adding it and setting:
fortune_files:
- default_file
No manual action is required.
π Fortune File Format
Each fortune must be on one or more lines separated by %, like so:
%
The best way to get a good idea is to get a lot of ideas.
%
Do or do not. There is no try.
%
To iterate is human, to recurse divine.
%
You may optionally add a title at the top of the file by starting the first line with #. The title will be printed before the random quote:
# Murphy's Laws
%
Anything that can go wrong will go wrong.
%
If there's a possibility of several things going wrong, the one that will cause the most damage will be the one to go wrong.
%
π License
This project is licensed under the MIT License.
Β© 2025 Alessandro Maestri
π‘ Contributing
Pull requests are welcome! If youβd like to add support for more languages, improve performance, or fix bugs, feel free to fork the repo and contribute.
π Acknowledgments
Inspired by the classic BSD fortune program. Built with β€οΈ in Rust.