🔍️ Appraisal2
Find out what my gems are worth!
- You, possibly
👣 How will this project approach the September 2025 hostile takeover of RubyGems? 🚑️
I've summarized my thoughts in [this blog post](https://dev.to/galtzo/hostile-takeover-of-rubygems-my-thoughts-5hlo).🌻 Synopsis
Appraisal2 integrates with bundler and rake to test your library against
different versions of dependencies in repeatable scenarios called “appraisals.”
Appraisal2 is designed to make it easy to check for regressions in your library
without interfering with day-to-day development using Bundler.
Appraisal2 is a hard fork of the venerable appraisal gem,
which thoughtbot maintained for many years.
Many thanks to thoughtbot,
and Joe Ferris, the original author!
Appraisal2 adds:
- support for
eval_gemfile - support for ORE as an alternative gem manager (faster than bundler!)
- For easy setup in Gitea Actions, Forgejo Actions, Codeberg Actions, or GitHub Actions check out appraisal-rb/setup-ruby-flash
- support for Ruby 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 (all removed, or planned-to-be, in thoughtbot’s
appraisal)- NOTE: The setup-ruby GH Action only ships support for Ruby 2.3+, so older Rubies are no longer tested in CI. Compatibility is assumed thanks to
enforcing the syntax for the oldest supported Ruby, which is Ruby v1.8. File a bug if you find something broken.
- NOTE: The setup-ruby GH Action only ships support for Ruby 2.3+, so older Rubies are no longer tested in CI. Compatibility is assumed thanks to
- Support for JRuby 9.4+
- updated and improved documentation
- many other fixes and improvements. See CHANGELOG for details.
💡 Info you can shake a stick at
| Tokens to Remember |
|
|---|---|
| Works with JRuby |
|
| Works with Truffle Ruby |
|
| Works with MRI Ruby 4 |
|
| Works with MRI Ruby 3 |
|
| Works with MRI Ruby 2 |
|
| Works with MRI Ruby 1 |
|
| Source |
|
| Documentation |
|
| Compliance |
|
| Style |
|
| Support |
![Live Chat on Discord][✉️discord-invite-img] |
| Enterprise Support |
💡Subscribe for support guarantees covering all FLOSS dependencies! 💡Tidelift is part of Sonar! 💡Tidelift pays maintainers to maintain the software you depend on! 📊 @Pointy Haired Boss: An enterprise support subscription is “never gonna let you down”, and supports open source maintainers! |
| Comrade BDFL 🎖️ |
|
... 💖 |
|
✨ Installation
Install the gem and add to the application’s Gemfile by executing:
$ bundle add appraisal2
If bundler is not being used to manage dependencies, install the gem by executing:
$ gem install appraisal2
In a RubyGem library
In your package’s .gemspec:
spec.add_development_dependency "appraisal2"
Note that gems must be bundled in the global namespace. Bundling gems to a
local location or vendoring plugins is not fully supported. If you do not want to
pollute the global namespace, one alternative is
RVM’s Gemsets.
🔒 Secure Installation
For Medium or High Security Installations
`appraisal2` is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by [stone_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with by following the instructions below. Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate: ```console gem cert --add <(curl -Ls https://raw.github.com/appraisal-rb/appraisal2/main/certs/pboling.pem) ``` You only need to do that once. Then proceed to install with: ```console gem install appraisal2 -P MediumSecurity ``` The `MediumSecurity` trust profile will verify signed gems, but allow the installation of unsigned dependencies. This is necessary because not all of `appraisal2`’s dependencies are signed, so we cannot use `HighSecurity`. If you want to up your security game full-time: ```console bundle config set --global trust-policy MediumSecurity ``` NOTE: Be prepared to track down certs for signed gems and add them the same way you added mine.🔧 Basic Setup
Setting up appraisal2 requires an Appraisals file (similar to a Gemfile) in
your project root, named “Appraisals” (note the case), and some slight changes
to your project’s Rakefile.
An Appraisals file consists of several appraisal definitions. An appraisal
definition is simply a list of gem dependencies. For example, to test with a
few versions of Rails:
appraise "rails-3" do
gem "rails", "3.2.14"
end
appraise "rails-4" do
gem "rails", "4.0.0"
end
The dependencies in your Appraisals file are combined with dependencies in
your Gemfile, so you don’t need to repeat anything that’s the same for each
appraisal. If something is specified in both the Gemfile and an appraisal, the
version from the appraisal takes precedence.
Examples of usage in the wild
Appraisal2 can be setup to achieve many different things, from testing against
different versions of services, like MySQL, Redis, or Memcached, and their drivers,
different versions of gems, different platforms, and running different types of validations
which each require a distinct set of gems.
It can also help developers to follow the official recommendation (since 2017) of the bundler team,
to commit the [main] Gemfile.lock for both apps and gems. It does this by giving you alternate gemfiles that won’t have their gemfiles/*.gemfile.lock committed, so you can simply commit the main one without breaking CI.
Having so many different use cases means it can be helpful to others to see how you have done your implementation. If you are willing to spend the time documenting, please send a PR to update this table with another Appraisal2-using project, linking to the specific workflows people can check to see how it is done!
| # | gem | locked / unlocked deps | analysis / services | SemVer / HEAD deps | Rubies | os |
|---|---|---|---|---|---|---|
| 1 |
omniauth-identity |
|
|
|
|
❌ |
| 2 |
rspec-stubbed_env |
|
|
|
❌ | |
| 3 |
silent_stream |
|
|
|
❌ | |
| 4 |
oauth2 |
|
|
|
|
|
⚒️ Basic Usage
Once you’ve configured the appraisals you want to use, you need to install the
dependencies for each appraisal:
$ bundle exec appraisal install
This will resolve, install, and lock the dependencies for that appraisal using
bundler. Once you have your dependencies set up, you can run any command in a
single appraisal:
$ bundle exec appraisal rails-3 rake test
This will run rake test using the dependencies configured for Rails 3. You can
also run each appraisal in turn:
$ bundle exec appraisal rake test
If you want to use only the dependencies from your Gemfile, just run rake
test as normal. This allows you to keep running with the latest versions of
your dependencies in quick test runs, but keep running the tests in older
versions to check for regressions.
In the case that you want to run all the appraisals by default when you run
rake, you can override your default Rake task by putting this into your Rakefile:
if !ENV["APPRAISAL_INITIALIZED"] && ENV.fetch("CI", "false").casecmp("false") == 0
task :default => :appraisal
end
(Appraisal2 sets APPRAISAL_INITIALIZED environment variable when it runs your
process. We put a check here to ensure that appraisal rake command should run
your real default task, which usually is your test task.)
Note that this may conflict with your CI setup if you decide to split the test
into multiple processes by Appraisal2 and you are using rake to run tests by
default.
Commands
appraisal clean # Remove all generated gemfiles and lockfiles from gemfiles folder
appraisal generate # Generate a gemfile for each appraisal
appraisal help [COMMAND] # Describe available commands or one specific command
appraisal install # Resolve and install dependencies for each appraisal
appraisal list # List the names of the defined appraisals
appraisal update [LIST_OF_GEMS] # Remove all generated gemfiles and lockfiles, resolve, and install dependencies again
appraisal version # Display the version and exit
Command Options
The install and update built-in commands support several options:
Important: These options apply only to Appraisal’s install and update commands.
They do not apply when running external commands like bundle install or bundle update.
| Option | Description |
|---|---|
--gem-manager, -g
|
Gem manager to use: bundler (default) or ore
|
--jobs, -j
|
Install gems in parallel using the given number of workers |
--retry |
Retry network and git requests that have failed (default: 1) |
--without |
A space-separated list of groups to skip during installation |
--full-index |
Run bundle install with the full-index argument |
--path |
Install gems in the specified directory |
Using Commands with Named Appraisals
Using Appraisal’s built-in commands with named appraisals
When using Appraisal’s install or update commands with a specific appraisal name,
place the appraisal name first, then the command, then any options:
# ✅ Correct order: appraisal <NAME> <COMMAND> [OPTIONS]
bundle exec appraisal rails-7 install --gem-manager=ore
bundle exec appraisal rails-7 update rails --gem-manager=ore
bundle exec appraisal rails-7 install --jobs=4
# ❌ Wrong order (won't work)
bundle exec appraisal install rails-7 --gem-manager=ore # Wrong order
More examples with Appraisal’s built-in commands:
# Install dependencies for a specific appraisal
bundle exec appraisal rails-7 install
# Install with options
bundle exec appraisal rails-7 install --gem-manager=ore --jobs=4
# Update all gems in a specific appraisal
bundle exec appraisal rails-7 update
# Update specific gems in a specific appraisal
bundle exec appraisal rails-7 update rails rack
bundle exec appraisal rails-7 update rails rack --gem-manager=ore
Running external commands with named appraisals
For running external commands (like rake test, rspec, etc.) with a specific appraisal,
the structure is the same: appraisal name first, then the command:
# Run any external command with a specific appraisal's dependencies
bundle exec appraisal <APPRAISAL_NAME> <COMMAND>
# Examples:
bundle exec appraisal rails-7 rake test
bundle exec appraisal rails-7 rspec
bundle exec appraisal rails-7 rubocop
# Note: External commands do NOT support appraisal options like --gem-manager
# This doesn't work and will fail:
bundle exec appraisal rails-7 bundle install --gem-manager=ore # ❌ Wrong
Key difference:
-
bundle exec appraisal rails-7 install --gem-manager=ore✅ → Uses Appraisal’s install command with ORE -
bundle exec appraisal rails-7 bundle install --gem-manager=ore❌ → Tries to run external bundle command (which doesn’t recognize--gem-manager)
🦀 Using Ore (Alternative Gem Manager)
Appraisal2 supports ORE as an alternative to Bundler
for dependency resolution and installation. Ore is a fast gem manager written in Go that aims
to be a drop-in replacement for Bundler.
Installing Ore
You can install ORE via:
# Install ORE Light (no Ruby required for download)
# Installs to ~/.local/bin by default (no sudo needed)
curl -fsSL https://raw.githubusercontent.com/contriboss/ore-light/master/scripts/install.sh | bash
# For system-wide installation to /usr/local/bin
curl -fsSL https://raw.githubusercontent.com/contriboss/ore-light/master/scripts/install.sh | bash -s -- --system
Using Ore with Appraisal2
The --gem-manager=ore option works only with Appraisal’s built-in install and update commands.
It does NOT work with external commands like bundle install.
✅ Using –gem-manager with Appraisal’s install/update commands
To use ORE instead of bundler for dependency installation, pass the --gem-manager=ore option:
# Install dependencies for ALL appraisals using ORE
bundle exec appraisal install --gem-manager=ore
# Update dependencies for ALL appraisals using ORE
bundle exec appraisal update --gem-manager=ore
# Install dependencies for a SPECIFIC appraisal using ORE
bundle exec appraisal <APPRAISAL_NAME> install --gem-manager=ore
# Update dependencies for a SPECIFIC appraisal using ORE
bundle exec appraisal <APPRAISAL_NAME> update <GEMS> --gem-manager=ore
You can also use the short form:
bundle exec appraisal install -g ore
bundle exec appraisal <APPRAISAL_NAME> install -g ore
❌ Do NOT use –gem-manager with external commands
The --gem-manager option cannot be used when running external commands like bundle install:
# ❌ WRONG - Don't try to pass --gem-manager to external commands
bundle exec appraisal coverage bundle install --gem-manager=ore
# ✅ RIGHT - Use appraisal's install command instead
bundle exec appraisal coverage install --gem-manager=ore
The difference:
-
bundle exec appraisal coverage install --gem-manager=ore→ Uses Appraisal’s install command with ORE -
bundle exec appraisal coverage bundle install --gem-manager=ore→ Tries to run externalbundle install(which doesn’t recognize--gem-manager)
Ore-Specific Options
When using ORE, some options are translated to ORE’s equivalents:
| Appraisal Option | Ore Equivalent | Notes |
|---|---|---|
--jobs=N |
-workers=N |
Only used when N > 1 |
--path=DIR |
-vendor=DIR |
Sets the gem installation directory |
--without=GROUPS |
-without=GROUP1,GROUP2 |
Groups are comma-separated in ORE |
--retry |
(ignored) | ORE handles retries internally |
--full-index |
(ignored) | Not applicable to ORE |
Example Workflow with ORE
# Generate appraisal gemfiles
bundle exec appraisal generate
# Install dependencies for ALL appraisals using ORE (faster than bundler)
bundle exec appraisal install --gem-manager=ore --jobs=4
# Install dependencies for a SPECIFIC appraisal using ORE
bundle exec appraisal rails-7 install --gem-manager=ore --jobs=4
# Run tests against all appraisals (uses dependencies from appraisal gemfiles)
bundle exec appraisal rspec
# Run tests against a specific appraisal (uses that appraisal's dependencies)
bundle exec appraisal rails-7 rspec
# Update a specific gem in ALL appraisals using ORE
bundle exec appraisal update rack --gem-manager=ore
# Update a specific gem in ONE appraisal using ORE
bundle exec appraisal rails-7 update rack --gem-manager=ore
Note: When running tests or other external commands, the dependencies are already
installed from the appraisal’s gemfile. You don’t need to (and can’t) pass --gem-manager
to external commands—it only works with Appraisal’s built-in install and update commands.
When to Use Ore
Ore can be particularly beneficial when:
- You have many appraisals and want faster installation
- You’re in a CI environment where installation speed matters
- You want to take advantage of ORE’s parallel resolution capabilities
Note that ORE must be installed separately and available in your PATH.
If you specify ORE and it is not available, appraisal2 will raise an error.
Troubleshooting ORE/Gem Manager Issues
Error: “Unknown switches –gem-manager=ore”
If you see an error like:
Unknown switches("--gem-manager=ore")
This usually means you’re trying to pass --gem-manager to an external command instead of
Appraisal’s built-in command.
❌ Wrong:
bundle exec appraisal coverage bundle install --gem-manager=ore
# Error: "Unknown switches --gem-manager=ore"
# The --gem-manager flag is being passed to the external 'bundle install' command,
# which doesn't recognize it.
✅ Correct:
bundle exec appraisal coverage install --gem-manager=ore
# Correct: Uses Appraisal's install command with ORE gem manager
Key point: The --gem-manager option only works with Appraisal’s built-in
install and update commands. It cannot be used with external commands like
bundle install, bundle update, or bundle exec rake/rspec.
If you need to install dependencies using ORE:
- Run
bundle exec appraisal <NAME> install --gem-manager=ore - Then run your tests:
bundle exec appraisal <NAME> rspec
Under the hood
Running appraisal install generates a Gemfile for each appraisal by combining
your root Gemfile with the specific requirements for each appraisal. These are
stored in the gemfiles directory, and should be added to version control to
ensure that versions within constraints of the Gemfile are always used.
When you prefix a command with appraisal, the command is run with the
appropriate Gemfile for that appraisal, ensuring the correct dependencies
are used.
Sharing Modular Gemfiles between Appraisals
New in appraisal2 (not possible in thoughtbot’s appraisal)
It is common for Appraisals to duplicate sets of gems, and sometimes it
makes sense to DRY this up into a shared, modular, gemfile.
In a scenario where you do not load your main Gemfile in your Appraisals,
but you want to declare your various gem sets for e.g.
%w(coverage test documentation audit) once each, you can re-use the same
modular gemfiles for local development by referencing them from the main
Gemfile.
To do this, use the eval_gemfile declaration within the necessary
appraise block in your Appraisals file, which will behave the same as
eval_gemfile does in a normal Gemfile.
Example Usage
You could put your modular gemfiles in the gemfiles directory, or nest
them in gemfiles/modular/*, which will be used for this example.
Gemfile
eval_gemfile "gemfiles/modular/audit.gemfile"
gemfiles/modular/audit.gemfile
# Many gems are dropping support for Ruby < 3.1,
# so we only want to run our security audit in CI on Ruby 3.1+
gem "bundler-audit", "~> 0.9.2"
# And other security audit gems...
Appraisals
appraise "ruby-2-7" do
gem "dummy"
end
appraise "ruby-3-0" do
gem "dummy"
end
appraise "ruby-3-1" do
gem "dummy"
eval_gemfile "modular/audit.gemfile"
end
appraise "ruby-3-2" do
gem "dummy"
eval_gemfile "modular/audit.gemfile"
end
appraise "ruby-3-3" do
gem "dummy"
eval_gemfile "modular/audit.gemfile"
end
appraise "ruby-3-4" do
gem "dummy"
eval_gemfile "modular/audit.gemfile"
end
Appraisal2.root.gemfile
source "https://gem.coop"
# Appraisal2 Root Gemfile is for running appraisal to generate the Appraisal2 Gemfiles
# We do not load the standard Gemfile, as it is tailored for local development,
# while appraisals are tailored for CI.
gemspec
gem "appraisal2"
Now when you need to update your appraisals:
BUNDLE_GEMFILE=Appraisal2.root.gemfile bundle exec appraisal update
Removing Gems using Appraisal2
It is common while managing multiple Gemfiles for dependencies to become deprecated and no
longer necessary, meaning they need to be removed from the Gemfile for a specific appraisal.
To do this, use the remove_gem declaration within the necessary appraise block in your
Appraisals file.
Example Usage
Gemfile
gem "rails", "~> 4.2"
group :test do
gem "rspec", "~> 4.0"
gem "test_after_commit"
end
Appraisals
appraise "rails-5" do
gem "rails", "~> 5.2"
group :test do
remove_gem "test_after_commit"
end
end
Using the Appraisals file defined above, this is what the resulting Gemfile will look like:
gem "rails", "~> 5.2"
group :test do
gem "rspec", "~> 4.0"
end
Customization
It is possible to customize the generated Gemfiles by adding a customize_gemfiles block to
your Appraisals file. The block must contain a hash of key/value pairs. Currently supported
customizations include:
- heading: a string that by default adds “# This file was generated by Appraisal2” to the top of each Gemfile, (the string will be commented for you)
- single_quotes: a boolean that controls if strings are single quoted in each Gemfile, defaults to false
You can also provide variables for substitution in the heading, based on each appraisal. Currently supported variables:
-
%{appraisal}: Becomes the name of each appraisal, e.g.rails-3 -
%{gemfile}: Becomes the filename of each gemfile, e.g.rails-3.gemfile -
%{gemfile_path}: Becomes the full path of each gemfile, e.g./path/to/project/gemfiles/rails-3.gemfile -
%{lockfile}: Becomes the filename of each lockfile, e.g.rails-3.gemfile.lock -
%{lockfile_path}: Becomes the full path of each lockfile, e.g./path/to/project/gemfiles/rails-3.gemfile.lock -
%{relative_gemfile_path}: Becomes the relative path of each gemfile, e.g.gemfiles/rails-3.gemfile -
%{relative_lockfile_path}: Becomes the relative path of each lockfile, e.g.gemfiles/rails-3.gemfile.lock
Example Usage
Appraisals
customize_gemfiles do
{
:single_quotes => true,
:heading => <<-HEADING,
frozen_string_literal: true
`%{gemfile}` has been generated by Appraisal2, do NOT modify it or `%{lockfile}` directly!
Make the changes to the "%{appraisal}" block in `Appraisals` instead. See the conventions at https://example.com/
HEADING
}
end
appraise "rails-3" do
gem "rails", "3.2.14"
end
Using the Appraisals file defined above, this is what the resulting Gemfile will look like:
# frozen_string_literal: true
# `rails-3.gemfile` has been generated by Appraisal2, do NOT modify it or `rails-3.gemfile.lock` directly!
# Make the changes to the "rails-3" block in `Appraisals` instead. See the conventions at https://example.com/
gem "rails", "3.2.14"
Version Control
When using Appraisal2, we recommend you check in the Gemfiles that Appraisal2
generates within the gemfiles directory, but exclude the lockfiles there
(*.gemfile.lock). The Gemfiles are useful when running your tests against a
continuous integration server.
Additionally, the Bundler team officially recommends
committing the main Gemfile.lock for both gems and libraries.
Circle CI Integration
In Circle CI you can override the default testing behavior.
You can configure Appraisal2 to execute your tests.
In order to this you can put the following configuration in your circle.yml file:
dependencies:
post:
- bundle exec appraisal install
test:
pre:
- bundle exec appraisal rake db:create
- bundle exec appraisal rake db:migrate
override:
- bundle exec appraisal rspec
Notice that we are running an rspec suite. You can customize your testing
command in the override section and use your favourite one.
🦷 FLOSS Funding
While appraisal-rb tools are free (libre) software, the project would benefit immensely from some funding.
Raising a monthly budget of… “dollars” would make the project more sustainable.
We welcome both individual and corporate sponsors! We also offer a
wide array of funding channels to account for your preferences
(although currently Open Collective is our preferred funding platform).
If you’re working in a company that’s making significant use of appraisal-rb tools we’d
appreciate it if you suggest to your company to become a appraisal-rb sponsor.
You can support the development of appraisal-rb tools via
GitHub Sponsors,
Liberapay,
PayPal,
Open Collective
and Tidelift.
| 📍 NOTE |
|---|
| If doing a sponsorship in the form of donation is problematic for your company from an accounting standpoint, we’d recommend the use of Tidelift, where you can get a support-like subscription instead. |
Open Collective for Individuals
Support us with a monthly donation and help us continue our activities. [Become a backer]
NOTE: kettle-readme-backers updates this list every day, automatically.
No backers yet. Be the first!
Open Collective for Organizations
Become a sponsor and get your logo on our README on GitHub with a link to your site. [Become a sponsor]
NOTE: kettle-readme-backers updates this list every day, automatically.
No sponsors yet. Be the first!
Another way to support open-source
I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈 cats).
If you work at a company that uses my work, please encourage them to support me as a corporate sponsor. My work on gems you use might show up in bundle fund.
I’m developing a new library, floss_funding, designed to empower open-source developers like myself to get paid for the work we do, in a sustainable way. Please give it a look.
Floss-Funding.dev: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags
🔐 Security
See SECURITY.md.
🤝 Contributing
If you need some ideas of where to help, you could work on adding more code coverage,
or if it is already 💯 (see below) check issues, or PRs,
or use the gem and think about how it could be better.
We so if you make changes, remember to update it.
See CONTRIBUTING.md for more detailed instructions.
🚀 Release Instructions
See CONTRIBUTING.md.
Code Coverage
🪇 Code of Conduct
Everyone interacting with this project’s codebases, issue trackers,
chat rooms and mailing lists agrees to follow the .
🌈 Contributors
Made with contributors-img.
Also see GitLab Contributors: https://gitlab.com/appraisal-rb/appraisal2/-/graphs/main
📌 Versioning
This Library adheres to .
Violations of this scheme should be reported as bugs.
Specifically, if a minor or patch version is released that breaks backward compatibility,
a new version should be immediately released that restores compatibility.
Breaking changes to the public API will only be introduced with new major versions.
dropping support for a platform is both obviously and objectively a breaking change
—Jordan Harband (@ljharb, maintainer of SemVer) in SemVer issue 716
I understand that policy doesn’t work universally (“exceptions to every rule!”),
but it is the policy here.
As such, in many cases it is good to specify a dependency on this library using
the Pessimistic Version Constraint with two digits of precision.
For example:
spec.add_dependency("appraisal2", "~> 3.0")
📌 Is "Platform Support" part of the public API? More details inside.
SemVer should, IMO, but doesn’t explicitly, say that dropping support for specific Platforms is a breaking change to an API, and for that reason the bike shedding is endless.
To get a better understanding of how SemVer is intended to work over a project’s lifetime, read this article from the creator of SemVer:
See CHANGELOG.md for a list of releases.
📄 License
The gem is available as open source under the terms of
the MIT License .
See LICENSE.txt for the official Copyright Notice.
© Copyright
-
Copyright (c) 2024 - 2026 Peter H. Boling, of
Galtzo.com
, and Appraisal2 contributors - Copyright (c) 2010 - 2013 Joe Ferris and thoughtbot, inc.
🤑 A request for help
Maintainers have teeth and need to pay their dentists.
After getting laid off in an RIF in March, and encountering difficulty finding a new one,
I began spending most of my time building open source tools.
I’m hoping to be able to pay for my kids’ health insurance this month,
so if you value the work I am doing, I need your support.
Please consider sponsoring me or the project.
To join the community or get help 👇️ Join the Discord.
To say “thanks!” ☝️ Join the Discord or 👇️ send money.
Please give the project a star ⭐ ♥.
Thanks for RTFM. ☺️