{"id":50728203,"url":"https://github.com/kettle-dev/kettle-dev","last_synced_at":"2026-06-10T06:01:44.931Z","repository":{"id":311365243,"uuid":"1042382652","full_name":"kettle-dev/kettle-dev","owner":"kettle-dev","description":"🍲 Setup a complete rake \u0026 dev harness for Ruby development; tasks for coverage, GHA console, linting, debugging, etc.","archived":false,"fork":false,"pushed_at":"2026-06-09T10:01:44.000Z","size":6273,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-09T11:18:24.364Z","etag":null,"topics":["ruby","rubygem","template"],"latest_commit_sha":null,"homepage":"https://kettle-dev.galtzo.com/","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kettle-dev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null},"funding":{"buy_me_a_coffee":"pboling","community_bridge":null,"github":["pboling"],"issuehunt":"pboling","ko_fi":"pboling","liberapay":"pboling","open_collective":"kettle-rb","patreon":"galtzo","polar":"pboling","thanks_dev":"u/gh/pboling","tidelift":"rubygems/kettle-dev"}},"created_at":"2025-08-21T23:49:45.000Z","updated_at":"2026-06-09T10:10:41.000Z","dependencies_parsed_at":"2026-03-19T03:07:21.613Z","dependency_job_id":null,"html_url":"https://github.com/kettle-dev/kettle-dev","commit_stats":null,"previous_names":["kettle-rb/kettle-dev","kettle-dev/kettle-dev"],"tags_count":108,"template":false,"template_full_name":null,"purl":"pkg:github/kettle-dev/kettle-dev","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kettle-dev%2Fkettle-dev","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kettle-dev%2Fkettle-dev/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kettle-dev%2Fkettle-dev/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kettle-dev%2Fkettle-dev/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kettle-dev","download_url":"https://codeload.github.com/kettle-dev/kettle-dev/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kettle-dev%2Fkettle-dev/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34139178,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-10T02:00:07.152Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ruby","rubygem","template"],"created_at":"2026-06-10T06:00:59.526Z","updated_at":"2026-06-10T06:01:44.917Z","avatar_url":"https://github.com/kettle-dev.png","language":"Ruby","funding_links":["https://buymeacoffee.com/pboling","https://github.com/sponsors/pboling","https://issuehunt.io/r/pboling","https://ko-fi.com/pboling","https://liberapay.com/pboling","https://opencollective.com/kettle-rb","https://patreon.com/galtzo","https://polar.sh/pboling","https://thanks.dev/u/gh/pboling","https://tidelift.com/funding/github/rubygems/kettle-dev","https://tidelift.com/badges/package/rubygems/kettle-dev","https://tidelift.com/subscription/pkg/rubygems-kettle-dev?utm_source=rubygems-kettle-dev\u0026utm_medium=referral\u0026utm_campaign=readme","https://liberapay.com/pboling/donate","https://opencollective.com/kettle-dev","https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20latte\u0026emoji=\u0026slug=pboling\u0026button_colour=FFDD00\u0026font_colour=000000\u0026font_family=Cookie\u0026outline_colour=000000\u0026coffee_colour=ffffff","https://www.buymeacoffee.com/pboling","https://www.paypal.com/paypalme/peterboling","https://blog.tidelift.com/tidelift-joins-sonar","https://issuehunt.io/u/pboling"],"categories":[],"sub_categories":[],"readme":"\u003ca href=\"https://github.com/kettle-dev\"\u003e\u003cimg alt=\"kettle-dev Logo by Aboling0, CC BY-SA 4.0\" src=\"https://logos.galtzo.com/assets/images/kettle-dev/avatar-128px.svg\" width=\"14%\" align=\"right\"/\u003e\u003c/a\u003e\n\n# 🍲 Kettle::Dev\n\n[![Version][👽versioni]][👽version] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: AGPL-3.0-only][📄license-img]][📄license] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![CodeCov Test Coverage][🏀codecovi]][🏀codecov] [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls] [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov] [![QLTY Maintainability][🏀qlty-mnti]][🏀qlty-mnt] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI Truffle Ruby][🚎9-t-wfi]][🚎9-t-wf] [![CI JRuby][🚎10-j-wfi]][🚎10-j-wf] [![Deps Locked][🚎13-🔒️-wfi]][🚎13-🔒️-wf] [![Deps Unlocked][🚎14-🔓️-wfi]][🚎14-🔓️-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf]\n\n`if ci_badges.map(\u0026:color).detect { it != \"green\"}` ☝️ [let me know][✉️discord-invite], as I may have missed the [discord notification][✉️discord-invite].\n\n---\n\n`if ci_badges.map(\u0026:color).all? { it == \"green\"}` 👇️ send money so I can do more of this. FLOSS maintenance is now my full-time job.\n\n[![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate at ko-fi.com][🖇kofi-img]][🖇kofi]\n\n\u003cdetails\u003e\n \u003csummary\u003e👣 How will this project approach the September 2025 hostile takeover of RubyGems? 🚑️\u003c/summary\u003e\n\nI've summarized my thoughts in [this blog post](https://dev.to/galtzo/hostile-takeover-of-rubygems-my-thoughts-5hlo).\n\n\u003c/details\u003e\n\n## 🌻 Synopsis \u003ca href=\"https://discord.gg/3qme4XHNKN\"\u003e\u003cimg alt=\"Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0\" src=\"https://logos.galtzo.com/assets/images/galtzo-floss/avatar-128px.svg\" width=\"8%\" align=\"right\"/\u003e\u003c/a\u003e \u003ca href=\"https://ruby-toolbox.com\"\u003e\u003cimg alt=\"ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5\" src=\"https://logos.galtzo.com/assets/images/ruby-lang/avatar-128px.svg\" width=\"8%\" align=\"right\"/\u003e\u003c/a\u003e\n\nKettle::Dev is the development, CI, changelog, and release harness used by\nkettle-rb gems. It installs rake tasks when loaded from a project's `Rakefile`,\nand it ships command-line tools for changelog preparation, release automation,\nmulti-forge git remotes, commit-message hooks, and Open Collective README\nupdates.\n\nAdd it to a gem's development dependencies, then load the rake integration:\n\n```ruby\n# Gemfile\ngroup :development, :test do\n  gem \"kettle-dev\", require: false\nend\n```\n\n```ruby\n# Rakefile\nrequire \"kettle/dev\"\n```\n\nFor RSpec projects, use the matching test harness from\n[kettle-test](https://github.com/kettle-rb/kettle-test):\n\n```ruby\nrequire \"kettle/test/rspec\"\n```\n\nProject setup and template refreshes are now owned by\n[kettle-jem](https://github.com/kettle-rb/kettle-jem), not kettle-dev:\n\n```console\ngem install kettle-jem\nkettle-jem setup\n```\n\nOnce a project is wired, the normal local development loop is:\n\n```console\nbin/rake\nbin/rake rubocop_gradual:autocorrect\nbin/rake yard\n```\n\nAnd the maintainer release flow is:\n\n```console\nbin/kettle-pre-release\nbin/kettle-changelog\nbin/kettle-release\n```\n\n### What kettle-dev provides\n\n- Rake task loading from `require \"kettle/dev\"`.\n- RuboCop Gradual, Reek, YARD, appraisal, local CI, benchmark, and coverage task wiring.\n- `kettle-changelog` for moving Unreleased changelog notes into a versioned release section with coverage and documentation stats.\n- `kettle-release` for the canonical kettle-rb release flow.\n- `kettle-pre-release` for release readiness checks.\n- `kettle-dvcs` for normalizing GitHub, GitLab, Codeberg, and aggregate remotes.\n- `kettle-commit-msg` for shared commit-message hook behavior.\n- `kettle-readme-backers` for Open Collective README sections.\n- `kettle-dev-setup` as a deprecated compatibility executable that exits with instructions to use kettle-jem.\n\n## 💡 Info you can shake a stick at\n\n| Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |\n|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| Works with JRuby | [![JRuby 9.2 Compat][💎jruby-9.2i]][🚎jruby-9.2-wf] [![JRuby 9.3 Compat][💎jruby-9.3i]][🚎jruby-9.3-wf] \u003cbr/\u003e [![JRuby 9.4 Compat][💎jruby-9.4i]][🚎jruby-9.4-wf] [![JRuby current Compat][💎jruby-c-i]][🚎10-j-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf]|\n| Works with Truffle Ruby | [![Truffle Ruby 22.3 Compat][💎truby-22.3i]][🚎truby-22.3-wf] [![Truffle Ruby 23.0 Compat][💎truby-23.0i]][🚎truby-23.0-wf] [![Truffle Ruby 23.1 Compat][💎truby-23.1i]][🚎truby-23.1-wf] \u003cbr/\u003e [![Truffle Ruby 24.2 Compat][💎truby-24.2i]][🚎truby-24.2-wf] [![Truffle Ruby 25.0 Compat][💎truby-25.0i]][🚎truby-25.0-wf] [![Truffle Ruby current Compat][💎truby-c-i]][🚎9-t-wf]|\n| Works with MRI Ruby 4 | [![Ruby 4.0 Compat][💎ruby-4.0i]][🚎11-c-wf] [![Ruby current Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf]|\n| Works with MRI Ruby 3 | [![Ruby 3.0 Compat][💎ruby-3.0i]][🚎ruby-3.0-wf] [![Ruby 3.1 Compat][💎ruby-3.1i]][🚎ruby-3.1-wf] [![Ruby 3.2 Compat][💎ruby-3.2i]][🚎ruby-3.2-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎ruby-3.3-wf] [![Ruby 3.4 Compat][💎ruby-3.4i]][🚎ruby-3.4-wf]|\n| Works with MRI Ruby 2 | [![Ruby 2.4 Compat][💎ruby-2.4i]][🚎ruby-2.4-wf] [![Ruby 2.5 Compat][💎ruby-2.5i]][🚎ruby-2.5-wf] [![Ruby 2.6 Compat][💎ruby-2.6i]][🚎ruby-2.6-wf] [![Ruby 2.7 Compat][💎ruby-2.7i]][🚎ruby-2.7-wf]|\n| Support \u0026 Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] |\n| Source | [![Source on GitLab.com][📜src-gl-img]][📜src-gl] [![Source on CodeBerg.org][📜src-cb-img]][📜src-cb] [![Source on Github.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ!][🧮kloc-img]][🧮kloc] |\n| Documentation | [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![YARD on Galtzo.com][📜docs-head-rd-img]][🚎yard-head] [![Maintainer Blog][🚂maint-blog-img]][🚂maint-blog] [![GitLab Wiki][📜gl-wiki-img]][📜gl-wiki] [![GitHub Wiki][📜gh-wiki-img]][📜gh-wiki] |\n| Compliance | [![License: AGPL-3.0-only][📄license-img]][📄license] [![Apache license compatibility: Category X][📄license-compat-img]][📄license-compat] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |\n| Style | [![Enforced Code Style Linter][💎rlts-img]][💎rlts] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog] [![Gitmoji Commits][📌gitmoji-img]][📌gitmoji] [![Compatibility appraised by: appraisal2][💎appraisal2-img]][💎appraisal2] |\n| Maintainer 🎖️ | [![Follow Me on LinkedIn][💖🖇linkedin-img]][💖🖇linkedin] [![Follow Me on Ruby.Social][💖🐘ruby-mast-img]][💖🐘ruby-mast] [![Follow Me on Bluesky][💖🦋bluesky-img]][💖🦋bluesky] [![Contact Maintainer][🚂maint-contact-img]][🚂maint-contact] [![My technical writing][💖💁🏼‍♂️devto-img]][💖💁🏼‍♂️devto] |\n| `...` 💖 | [![Find Me on WellFound:][💖✌️wellfound-img]][💖✌️wellfound] [![Find Me on CrunchBase][💖💲crunchbase-img]][💖💲crunchbase] [![My LinkTree][💖🌳linktree-img]][💖🌳linktree] [![More About Me][💖💁🏼‍♂️aboutme-img]][💖💁🏼‍♂️aboutme] [🧊][💖🧊berg] [🐙][💖🐙hub] [🛖][💖🛖hut] [🧪][💖🧪lab] |\n\n### Compatibility\n\nCompatible with MRI Ruby 2.4.0+, and concordant releases of JRuby, and TruffleRuby.\nCI workflows and Appraisals are generated for MRI Ruby 2.4+.\nThis test floor is configured by `ruby.test_minimum` in `.kettle-jem.yml` and\nmay be higher than the gem's runtime compatibility floor when legacy Rubies are\nnot practical for the current toolchain.\n\n| 🚚 _Amazing_ test matrix was brought to you by | 🔎 appraisal2 🔎 and the color 💚 green 💚 |\n|------------------------------------------------|--------------------------------------------------------|\n| 👟 Check it out! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ |\n\n### Federated DVCS\n\n\u003cdetails markdown=\"1\"\u003e\n \u003csummary\u003eFind this repo on federated forges (Coming soon!)\u003c/summary\u003e\n\n| Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |\n|-------------------------------------------------|-----------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------|\n| 🧪 [kettle-dev/kettle-dev on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |\n| 🧊 [kettle-dev/kettle-dev on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |\n| 🐙 [kettle-dev/kettle-dev on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |\n| 🎮️ [Discord Server][✉️discord-invite] | [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] | [Let's][✉️discord-invite] | [talk][✉️discord-invite] | [about][✉️discord-invite] | [this][✉️discord-invite] | [library!][✉️discord-invite] |\n\n\u003c/details\u003e\n\n[gh-discussions]: https://github.com/kettle-dev/kettle-dev/discussions\n\n### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/kettle-dev)](https://tidelift.com/subscription/pkg/rubygems-kettle-dev?utm_source=rubygems-kettle-dev\u0026utm_medium=referral\u0026utm_campaign=readme)\n\nAvailable as part of the Tidelift Subscription.\n\n\u003cdetails markdown=\"1\"\u003e\n \u003csummary\u003eNeed enterprise-level guarantees?\u003c/summary\u003e\n\nThe maintainers of this and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use.\n\n[![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]\n\n- 💡Subscribe for support guarantees covering _all_ your FLOSS dependencies\n- 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]\n- 💡Tidelift pays maintainers to maintain the software you depend on!\u003cbr/\u003e📊`@`Pointy Haired Boss: An [enterprise support][🏙️entsup-tidelift] subscription is \"[never gonna let you down][🧮kloc]\", and *supports* open source maintainers\n\nAlternatively:\n\n- [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]\n- [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork]\n- [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor]\n\n\u003c/details\u003e\n\n## ✨ Installation\n\nInstall the gem and add to the application's Gemfile by executing:\n\n```console\nbundle add kettle-dev\n```\n\nIf bundler is not being used to manage dependencies, install the gem by executing:\n\n```console\ngem install kettle-dev\n```\n\n## ⚙️ Configuration\n\nKettle-dev has two integration surfaces:\n\n- Executable scripts in `exe/`, or binstubs generated from them, can run when\n  `kettle-dev` is installed and loadable.\n- Rake tasks are registered by adding `kettle-dev` to the project's development\n  dependencies and requiring `kettle/dev` from the project's `Rakefile`.\n\n```ruby\ngroup :development, :test do\n  gem \"kettle-dev\", require: false\nend\n```\n\n```ruby\nrequire \"kettle/dev\"\n```\n\n### RSpec\n\nThis gem integrates tightly with [kettle-test](https://github.com/kettle-rb/kettle-test).\n\n```ruby\nrequire \"kettle/test/rspec\"\n\n# ... any other config you need to do.\n\n# NOTE: Gemfiles for older rubies (\u003c 2.7) won't have kettle-soup-cover.\n#       The rescue LoadError handles that scenario.\nbegin\n  require \"kettle-soup-cover\"\n  require \"simplecov\" if Kettle::Soup::Cover::DO_COV # `.simplecov` is run here!\nrescue LoadError =\u003e error\n  # check the error message, and re-raise if not what is expected\n  raise error unless error.message.include?(\"kettle\")\nend\n\n# This gem (or app)\nrequire \"gem-under-test\"\n```\n\n### Rakefile\n\nAdd to your `Rakefile`:\n\n```ruby\nrequire \"kettle/dev\"\n```\n\nThis loads the kettle-dev rake task set. Current project setup and template\nrefreshes should be run through kettle-jem:\n\n```console\ngem install kettle-jem\nkettle-jem setup\n```\n\n`kettle-dev-setup` is still shipped for compatibility, but it now exits with a\nmessage explaining that setup and templating moved to kettle-jem.\n\nUseful registered tasks include:\n\n- `rubocop_gradual:autocorrect` and `rubocop_gradual:check`\n- `reek` and `reek:update`\n- `yard`\n- `appraisal:install`, `appraisal:generate`, `appraisal:update`, and `appraisal:reset`\n- `ci:act`\n- `bench`\n- `kettle:jem:template` and `kettle:jem:selftest`, when kettle-jem's task integration is available\n\nInstall binstubs when a project wants local `bin/kettle-*` commands:\n\n```console\nbundle binstubs kettle-dev --path bin\n```\n\n### Environment Variables\n\nBelow are the primary environment variables recognized by kettle-dev (and its integrated tools). Unless otherwise noted, set boolean values to the string \"true\" to enable.\n\nGeneral/runtime\n\n- `DEBUG`: Enable extra internal logging for this library (default: false)\n- `REQUIRE_BENCH`: Enable `require_bench` to profile requires (default: false)\n- `CI`: When set to true, adjusts default rake tasks toward CI behavior\n\nCoverage (kettle-soup-cover / SimpleCov)\n\n- `K_SOUP_COV_DO`: Enable coverage collection (default: true in .envrc)\n- `K_SOUP_COV_FORMATTERS`: Comma-separated list of formatters (html, xml, rcov, lcov, json, tty)\n- `K_SOUP_COV_MIN_LINE`: Minimum line coverage threshold (integer, e.g., 100)\n- `K_SOUP_COV_MIN_BRANCH`: Minimum branch coverage threshold (integer, e.g., 100)\n- `K_SOUP_COV_MIN_HARD`: Fail the run if thresholds are not met (true/false)\n- `K_SOUP_COV_MULTI_FORMATTERS`: Enable multiple formatters at once (true/false)\n- `K_SOUP_COV_OPEN_BIN`: Path to browser opener for HTML (empty disables auto-open)\n- `MAX_ROWS`: Limit console output rows for simplecov-console (e.g., 1)\n\nTip: When running a single spec file locally, you may want `K_SOUP_COV_MIN_HARD=false` to avoid failing thresholds for a partial run.\n\nGitHub API and CI helpers\n\n- `GITHUB_TOKEN` or `GH_TOKEN`: Token used by `ci:act` and release workflow checks to query GitHub Actions status at higher rate limits\n- `GITLAB_TOKEN` or `GL_TOKEN`: Token used by `ci:act` and CI monitor to query GitLab pipeline status\n\nReleasing and signing\n\n- `SKIP_GEM_SIGNING`: If set, skip gem signing during build/release\n- `GEM_CERT_USER`: Username for selecting your public cert in `certs/\u003cUSER\u003e.pem` (defaults to $USER)\n- `SOURCE_DATE_EPOCH`: Reproducible build timestamp. `kettle-release` will set this automatically for the session.\n\nGit hooks and commit message helpers (exe/kettle-commit-msg)\n\n- `GIT_HOOK_BRANCH_VALIDATE`: Branch name validation mode (e.g., `jira`) or `false` to disable\n- `GIT_HOOK_FOOTER_APPEND`: Append a footer to commit messages when goalie allows (true/false)\n- `GIT_HOOK_FOOTER_SENTINEL`: Required when footer append is enabled — a unique first-line sentinel to prevent duplicates\n- `GIT_HOOK_FOOTER_APPEND_DEBUG`: Extra debug output in the footer template (true/false)\n\nFor a quick starting point, this repository’s `.envrc` shows sane defaults, and `.env.local` can override them locally.\n\n## 🔧 Basic Usage\n\nCommon local workflows:\n\n- `bundle exec rake` runs the curated default task set. Locally this favors\n  autocorrection where supported; with `CI=true` it favors check-only behavior.\n- `bin/rspec` or `bundle exec rspec` runs specs.\n- `K_SOUP_COV_MIN_HARD=false bin/rspec spec/path/to/file_spec.rb` is useful for\n  focused spec runs that should not fail whole-suite coverage thresholds.\n- `bundle exec rake rubocop_gradual:autocorrect` applies gradual RuboCop fixes.\n- `bundle exec rake rubocop_gradual:check` is the CI-friendly RuboCop Gradual task.\n- `bundle exec rake reek` and `bundle exec rake reek:update` run or refresh Reek.\n- `bundle exec rake yard` builds API documentation.\n- `bundle exec rake appraisal:install` performs first-time Appraisal setup.\n- `bundle exec rake appraisal:generate` regenerates Appraisal gemfiles.\n- `bundle exec rake appraisal:update` updates Appraisal locks and applies gradual RuboCop autocorrect.\n- `bundle exec rake appraisal:reset` removes Appraisal lockfiles below `gemfiles/`.\n- `kettle-bump patch` bumps the current gem's patch version before running\n  `kettle-changelog`.\n\nGitHub Actions local runner helper:\n\n- `bundle exec rake ci:act` opens an interactive workflow selector using\n  `.github/workflows` and live CI status when tokens are available.\n- `bundle exec rake ci:act[loc]` selects by short code.\n- `bundle exec rake ci:act[locked_deps.yml]` selects by workflow filename.\n- Set `GITHUB_TOKEN` or `GH_TOKEN` for GitHub Actions API status.\n- Set `GITLAB_TOKEN` or `GL_TOKEN` for GitLab pipeline status.\n\nProject automation and template refreshes:\n\n- Use `kettle-jem setup` for first-time setup and `kettle-jem install` for\n  full template refreshes.\n- When kettle-jem's rake integration is installed, run `bundle exec rake kettle:jem:template`\n  to refresh template-managed files.\n- `kettle-dev-setup` is deprecated and intentionally exits with a migration\n  message pointing to kettle-jem.\n\n### kettle-dvcs (normalize multi-forge remotes)\n\n- Script: `exe/kettle-dvcs` (install binstubs for convenience: `bundle binstubs kettle-dev --path bin`)\n- Purpose: Normalize git remotes across GitHub, GitLab, and Codeberg, and create an `all` remote that pushes to all and fetches only from your chosen origin.\n- Assumptions: org and repo names are identical across forges.\n  Usage:\n\n\u003c!-- end list --\u003e\n\n```console\nkettle-dvcs [options] [ORG] [REPO]\n```\n\nOptions:\n\n- `--origin [github|gitlab|codeberg]` Which forge to use as `origin` (default: github)\n- `--protocol [ssh|https]` URL style (default: ssh)\n- `--github-name NAME` Remote name for GitHub when not origin (default: gh)\n- `--gitlab-name NAME` Remote name for GitLab (default: gl)\n- `--codeberg-name NAME` Remote name for Codeberg (default: cb)\n- `--force` Non-interactive; accept defaults, and do not prompt for ORG/REPO\n  Examples:\n- Default, interactive (infers ORG/REPO from an existing remote when possible):\n  ```console\n  kettle-dvcs\n  ```\n- Non-interactive with explicit org/repo:\n  ```console\n  kettle-dvcs --force my-org my-repo\n  ```\n- Use GitLab as origin and HTTPS URLs:\n  ```console\n  kettle-dvcs --origin gitlab --protocol https my-org my-repo\n  ```\n\nWhat it does:\n\n- Ensures remotes exist and have consistent URLs for each forge.\n- Renames existing remotes when their URL already matches the desired target but their name does not (e.g., `gitlab` -\\\u003e `gl`).\n- Creates/refreshes an `all` remote that:\n    - fetches only from your chosen `origin` forge.\n    - has pushurls configured for all three forges so `git push all \u003cbranch\u003e` updates all mirrors.\n- Prints `git remote -v` at the end.\n- Attempts to `git fetch` each forge remote to check availability:\n    - If all succeed, the README’s federated DVCS summary line has “(Coming soon\\!)” removed.\n    - If any fail, the script prints import links to help you create a mirror on that forge.\n\n### Releasing (maintainers)\n\n- Script: `exe/kettle-release` (run as `kettle-release`)\n- Purpose: guided release helper that:\n    - Runs `kettle-pre-release` before the numbered release steps on full releases, aborting before release setup if any pre-release gate fails.\n    - Runs sanity checks (`bin/setup`, `bin/rake`), confirms version/changelog, optionally updates Appraisals, regenerates docs via `bin/rake yard`, commits “🔖 Prepare release vX.Y.Z”.\n    - Optionally runs your CI locally with `act` before any push:\n        - Enable with env: `K_RELEASE_LOCAL_CI=\"true\"` (run automatically) or `K_RELEASE_LOCAL_CI=\"ask\"` (prompt \\[Y/n\\]).\n        - Select workflow with `K_RELEASE_LOCAL_CI_WORKFLOW` (with or without .yml/.yaml). Defaults to `locked_deps.yml` if present; otherwise the first workflow discovered.\n        - On failure, the release prep commit is soft-rolled-back (`git reset --soft HEAD^`) and the process aborts.\n    - Ensures trunk sync and rebases feature as needed, pushes, monitors GitHub Actions with a progress bar, and merges feature to trunk on success.\n    - Exports `SOURCE_DATE_EPOCH`, builds (optionally signed), creates gem checksums, and runs `bundle exec rake release` (prompts for signing key + RubyGems MFA OTP as needed).\n- Options:\n    - `start_step` map (skip directly to a phase):\n        1.  Verify Bundler \\\u003e= 2.7 (always runs; start at 1 to do everything)\n        2.  Detect version; RubyGems sanity check; confirm CHANGELOG/version; sync copyright years; update badges/headers\n        3.  Run bin/setup\n        4.  Run bin/rake (default task)\n        5.  Run bin/rake appraisal:update if Appraisals present, then bin/rake yard\n        6.  Ensure git user configured; commit release prep\n        7.  Optional local CI with `act` (controlled by `K_RELEASE_LOCAL_CI`)\n        8.  Ensure trunk in sync across remotes; rebase feature as needed\n        9.  Push current branch to remotes (or 'all' remote)\n        10. Monitor CI after push; abort on failures\n        11. Merge feature into trunk and push\n        12. Checkout trunk and pull latest\n        13. Gem signing checks/guidance (skip with `SKIP_GEM_SIGNING=true`)\n        14. Build gem (bundle exec rake build)\n        15. Release gem (bundle exec rake release)\n        16. Generate and validate checksums (`bin/gem_checksums`)\n        17. Push checksum commit\n        18. Create GitHub Release (requires `GITHUB_TOKEN`)\n        19. Push tags to remotes (final)\n- Examples:\n    - After intermittent CI failure, restart from monitoring: `bundle exec kettle-release start_step=10`\n    - After fixing a failed pre-release gate, rerun from the top: `bundle exec kettle-release`\n- Tips:\n    - The commit message helper `exe/kettle-commit-msg` prefers project-local `.git-hooks` (then falls back to `~/.git-hooks`).\n    - The goalie file `commit-subjects-goalie.txt` controls when a footer is appended; customize `footer-template.erb.txt` as you like.\n\n### Changelog generator\n\n- Script: `exe/kettle-bump` (run as `kettle-bump`)\n- Purpose: Bumps the current single gem's `lib/**/version.rb` before changelog\n  preparation. It accepts an exact version or `major`, `minor`, or `patch`.\n- Usage:\n    - `kettle-bump patch`\n    - `kettle-bump 1.2.4 --from 1.2.3`\n    - `kettle-bump minor --dry-run`\n    - `kettle-bump patch --check`\n- Behavior:\n    - Writes by default; use `--dry-run` to preview or `--check` to fail when a\n      bump would change files.\n    - Updates literal `spec.version = \"...\"` assignments in the gemspec when\n      they match the current version. Dynamic gemspec versions are left alone.\n    - Uses the same `K_CHANGELOG_VERSION_FILE` override as `kettle-changelog`\n      when a project needs to point at a specific version file.\n\n- Script: `exe/kettle-changelog` (run as `kettle-changelog`)\n- Purpose: Generates a new CHANGELOG.md section for the current version read from `lib/**/version.rb`, moves notes from the Unreleased section, and updates comparison links.\n- Prerequisites:\n    - `coverage/coverage.json` present (generate with: `K_SOUP_COV_FORMATTERS=\"json\" bin/rspec`).\n    - `bin/rake yard` available, to compute documentation coverage.\n- Usage:\n    - `kettle-changelog`\n- Behavior:\n    - Reads version from the unique `lib/**/version.rb` in the project.\n    - Moves entries from the `[Unreleased]` section into a new `[#.#.#] - YYYY-MM-DD` section.\n    - Prepends 4 lines with TAG, line coverage, branch coverage, and percent documented.\n    - Converts any GitLab-style compare links at the bottom to GitHub style, adds new tag/compare links for the new release and a temporary tag reference `[X.Y.Zt]`.\n\n### Pre-release checks\n\n- Script: `exe/kettle-gha-sha-pins` (run as `kettle-gha-sha-pins`)\n- Purpose: Validate and optionally update GitHub Actions `uses:` refs to pinned\n  SHAs and current allowed release versions.\n- Usage:\n    - `kettle-gha-sha-pins`\n    - `kettle-gha-sha-pins --check`\n    - `kettle-gha-sha-pins --write --upgrade patch`\n- Behavior:\n    - Human output shows discovery, workflow scan, and action-resolution progress\n      on STDERR, including per-action timing via `ruby-progressbar`, then prints\n      the final report on STDOUT.\n    - Action metadata is resolved with the GitHub REST API and cached per\n      `owner/repo` action so duplicate uses of the same action reuse one\n      resolution plan.\n    - The outdated summary reports newer releases even when `--upgrade patch` or\n      `--upgrade minor` limits the write target to a safer release line.\n    - JSON output keeps progress disabled by default so STDOUT remains parseable.\n      Use `--progress` to force progress or `--no-progress` to suppress it.\n    - `--check` exits non-zero when workflow action pins are stale or mutable and\n      prints a recommended `kettle-gha-sha-pins --write --upgrade patch` command.\n\n- Script: `exe/kettle-pre-release` (run as `kettle-pre-release`)\n- Purpose: Run a suite of pre-release validations to catch avoidable mistakes (resumable by check number).\n- Usage:\n    - `kettle-pre-release [--check-num N]`\n    - Short option: `kettle-pre-release -cN`\n- Options:\n    - `--check-num N` Start from check number N (default: 1)\n- Checks:\n    - 1) Validate GitHub Actions workflow action refs with `kettle-gha-sha-pins --check`; if pins are stale, it prints an outdated-actions summary, exits non-zero, and recommends `kettle-gha-sha-pins --write --upgrade patch`.\n    - 2) Normalize Markdown image URLs.\n    - 3) Validate that all image URLs referenced by Markdown files resolve (HTTP HEAD).\n\n### Commit message helper (git hook)\n\n- Script: `exe/kettle-commit-msg` (run by git as `.git/hooks/commit-msg`)\n- Purpose: Append a standardized footer and optionally enforce branch naming rules when configured.\n- Usage:\n    - Git invokes this with the path to the commit message file: `kettle-commit-msg .git/COMMIT_EDITMSG`\n    - Install hook templates through kettle-jem setup/templating, then point git at the resulting hook path.\n- Behavior:\n    - When `GIT_HOOK_BRANCH_VALIDATE=jira`, validates the current branch matches the pattern: `^(hotfix|bug|feature|candy)/[0-9]{8,}-…`.\n        - If it matches and the commit message lacks the numeric ID, appends `[\u003ctype\u003e][\u003cid\u003e]`.\n    - Always invokes `Kettle::Dev::GitCommitFooter.render` to potentially append a footer if allowed by the goalie.\n    - Prefers project-local `.git-hooks` templates; falls back to `~/.git-hooks`.\n- Environment:\n    - `GIT_HOOK_BRANCH_VALIDATE` Branch rule (e.g., `jira`) or `false` to disable.\n    - `GIT_HOOK_FOOTER_APPEND` Enable footer auto-append when goalie allows (true/false).\n    - `GIT_HOOK_FOOTER_SENTINEL` Required marker to avoid duplicate appends when enabled.\n    - `GIT_HOOK_FOOTER_APPEND_DEBUG` Extra debug output in the footer template (true/false).\n\n### Project bootstrap installer\n\n- Script: `exe/kettle-dev-setup` (run as `kettle-dev-setup`)\n- Status: Deprecated compatibility shim.\n- Purpose: Direct users to kettle-jem, which now owns setup and templating.\n- Usage:\n    - `kettle-dev-setup`\n- Behavior:\n    - Prints migration instructions.\n    - Exits non-zero.\n    - Does not modify the destination repository.\n- Replacement:\n    - `gem install kettle-jem`\n    - `kettle-jem setup`\n\n### Open Collective README updater\n\n- Script: `exe/kettle-readme-backers` (run as `kettle-readme-backers`)\n- Purpose: Updates README sections for Open Collective backers (individuals) and sponsors (organizations) by fetching live data from your collective.\n- Tags updated in README.md (first match wins for backers):\n    - The default tag prefix is `OPENCOLLECTIVE`, and it is configurable:\n        - ENV: `KETTLE_DEV_BACKER_README_OSC_TAG=\"OPENCOLLECTIVE\"`\n        - YAML (.opencollective.yml): `readme-osc-tag: \"OPENCOLLECTIVE\"`\n        - The resulting markers become: `\u003c!-- \u003cTAG\u003e:START --\u003e … \u003c!-- \u003cTAG\u003e:END --\u003e`, `\u003c!-- \u003cTAG\u003e-INDIVIDUALS:START --\u003e … \u003c!-- \u003cTAG\u003e-INDIVIDUALS:END --\u003e`, and `\u003c!-- \u003cTAG\u003e-ORGANIZATIONS:START --\u003e … \u003c!-- \u003cTAG\u003e-ORGANIZATIONS:END --\u003e`.\n        - ENV overrides YAML.\n    - Backers (Individuals): `\u003c!-- \u003cTAG\u003e:START --\u003e … \u003c!-- \u003cTAG\u003e:END --\u003e` or `\u003c!-- \u003cTAG\u003e-INDIVIDUALS:START --\u003e … \u003c!-- \u003cTAG\u003e-INDIVIDUALS:END --\u003e`\n    - Sponsors (Organizations): `\u003c!-- \u003cTAG\u003e-ORGANIZATIONS:START --\u003e … \u003c!-- \u003cTAG\u003e-ORGANIZATIONS:END --\u003e`\n- Handle resolution:\n    1.  `OPENCOLLECTIVE_HANDLE` environment variable, if set\n    2.  `opencollective.yml` in the project root (e.g., `collective: \"kettle-rb\"` in this repo)\n- Usage:\n    - `exe/kettle-readme-backers`\n    - `OPENCOLLECTIVE_HANDLE=my-collective exe/kettle-readme-backers`\n- Behavior:\n    - Writes to README.md only if content between the tags would change.\n    - If neither the backers nor sponsors tags are present, prints a helpful warning and exits with status 2.\n    - When there are no entries, inserts a friendly placeholder: \"No backers yet. Be the first\\!\" or \"No sponsors yet. Be the first\\!\".\n    - When updates are written and the repository is a git work tree, the script stages README.md and commits with a message thanking new backers and subscribers, including mentions for any newly added backers and subscribers (GitHub @handles when their website/profile is a github.com URL; otherwise their name).\n    - Customize the commit subject via env var: `KETTLE_README_BACKERS_COMMIT_SUBJECT=\"💸 Thanks 🙏 to our new backers 🎒 and subscribers 📜\"`.\n        - Or via .opencollective.yml: set `readme-backers-commit-subject: \"💸 Thanks 🙏 to our new backers 🎒 and subscribers 📜\"`.\n        - Precedence: ENV overrides .opencollective.yml; if neither is set, a sensible default is used.\n        - Note: When used with the provided `.git-hooks`, the subject should start with a gitmoji character (see [gitmoji][📌gitmoji]).\n- Tip:\n    - Run this locally before committing to keep your README current, or schedule it in CI to refresh periodically.\n    - It runs automatically on a once-a-week schedule by the .github/workflows/opencollective.yml workflow that is part of the kettle-jem template.\n- Authentication requirement:\n    - When running in CI with the provided workflow, you must provide an organization-level Actions secret named `README_UPDATER_TOKEN`.\n        - Create it under your GitHub organization settings: `https://github.com/organizations/\u003cYOUR_ORG\u003e/settings/secrets/actions`.\n        - The updater will look for `REPO` or `GITHUB_REPOSITORY` (both usually set by GitHub Actions) to infer `\u003cYOUR_ORG\u003e` for guidance.\n        - If `README_UPDATER_TOKEN` is missing, the tool prints a helpful error to STDERR and aborts, including a direct link to the expected org settings page.\n\n## 🔐 Security\n\nSee [SECURITY.md][🔐security].\n\n## 🤝 Contributing\n\nIf you need some ideas of where to help, you could work on adding more code coverage,\nor if it is already 💯 (see [below](#code-coverage)) check [issues][🤝gh-issues] or [PRs][🤝gh-pulls],\nor use the gem and think about how it could be better.\n\nWe [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.\n\nSee [CONTRIBUTING.md][🤝contributing] for more detailed instructions.\n\n### 🚀 Release Instructions\n\nSee [CONTRIBUTING.md][🤝contributing].\n\n### Code Coverage\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003eCoverage service badges\u003c/summary\u003e\n\n[![Coverage Graph][🏀codecov-g]][🏀codecov]\n\n[![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls]\n\n[![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov]\n\n\u003c/details\u003e\n\n### 🪇 Code of Conduct\n\nEveryone interacting with this project's codebases, issue trackers,\nchat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].\n\n## 🌈 Contributors\n\n[![Contributors][🖐contributors-img]][🖐contributors]\n\nMade with [contributors-img][🖐contrib-rocks].\n\nAlso see GitLab Contributors: [https://gitlab.com/kettle-dev/kettle-dev/-/graphs/main][🚎contributors-gl]\n\n\u003cdetails\u003e\n \u003csummary\u003e⭐️ Star History\u003c/summary\u003e\n\n\u003ca href=\"https://star-history.com/kettle-dev/kettle-dev\u0026Date\"\u003e\n \u003cpicture\u003e\n \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://api.star-history.com/svg?repos=kettle-dev/kettle-dev\u0026type=Date\u0026theme=dark\" /\u003e\n \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://api.star-history.com/svg?repos=kettle-dev/kettle-dev\u0026type=Date\" /\u003e\n \u003cimg alt=\"Star History Chart\" src=\"https://api.star-history.com/svg?repos=kettle-dev/kettle-dev\u0026type=Date\" /\u003e\n \u003c/picture\u003e\n\u003c/a\u003e\n\n\u003c/details\u003e\n\n## 📌 Versioning\n\nThis library follows [![Semantic Versioning 2.0.0][📌semver-img]][📌semver] for its public API where practical.\nFor most applications, prefer the [Pessimistic Version Constraint][📌pvc] with two digits of precision.\n\nFor example:\n\n```ruby\nspec.add_dependency(\"kettle-dev\", \"~\u003e 2.0\")\n```\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003e📌 Is \"Platform Support\" part of the public API? More details inside.\u003c/summary\u003e\n\nDropping support for a platform can be a breaking change for affected users.\nIf a release changes supported platforms, it should be called out clearly in the changelog and versioned with that impact in mind.\n\nTo get a better understanding of how SemVer is intended to work over a project's lifetime,\nread this article from the creator of SemVer:\n\n- [\"Major Version Numbers are Not Sacred\"][📌major-versions-not-sacred]\n\n\u003c/details\u003e\n\nSee [CHANGELOG.md][📌changelog] for a list of releases.\n\n## 📄 License\n\nThe gem is available under the following license: [AGPL-3.0-only](AGPL-3.0-only.md).\nSee [LICENSE.md][📄license] for details.\n\nIf none of the available licenses suit your use case, please [contact us](mailto:floss@galtzo.com) to discuss a custom commercial license.\n\n### © Copyright\n\nSee [LICENSE.md][📄license] for the official copyright notice.\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003eCopyright holders\u003c/summary\u003e\n\n- Copyright (c) 2023, 2025-2026 Peter H. Boling\n\n\u003c/details\u003e\n\n## 🤑 A request for help\n\nMaintainers have teeth and need to pay their dentists.\nAfter getting laid off in an RIF in March, and encountering difficulty finding a new one,\nI began spending most of my time building open source tools.\nI'm hoping to be able to pay for my kids' health insurance this month,\nso if you value the work I am doing, I need your support.\nPlease consider sponsoring me or the project.\n\nTo join the community or get help 👇️ Join the Discord.\n\n[![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]\n\nTo say \"thanks!\" ☝️ Join the Discord or 👇️ send money.\n\n[![Sponsor kettle-dev/kettle-dev on Open Source Collective][🖇osc-all-bottom-img]][🖇osc] 💌 [![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal]\n\n### Please give the project a star ⭐ ♥.\n\nMany parts of this project are actively managed by a [kettle-jem](https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/kettle-jem) smart template utilizing [StructuredMerge.org](https://structuredmerge.org) merge contracts.\n\nThanks for RTFM. ☺️\n\n[⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay\u0026color=a51611\u0026style=flat\n[⛳liberapay-bottom-img]: https://img.shields.io/liberapay/goal/pboling.svg?style=for-the-badge\u0026logo=liberapay\u0026color=a51611\n[⛳liberapay]: https://liberapay.com/pboling/donate\n[🖇osc-all-img]: https://img.shields.io/opencollective/all/kettle-dev\n[🖇osc-sponsors-img]: https://img.shields.io/opencollective/sponsors/kettle-dev\n[🖇osc-backers-img]: https://img.shields.io/opencollective/backers/kettle-dev\n[🖇osc-backers]: https://opencollective.com/kettle-dev#backer\n[🖇osc-backers-i]: https://opencollective.com/kettle-dev/backers/badge.svg?style=flat\n[🖇osc-sponsors]: https://opencollective.com/kettle-dev#sponsor\n[🖇osc-sponsors-i]: https://opencollective.com/kettle-dev/sponsors/badge.svg?style=flat\n[🖇osc-all-bottom-img]: https://img.shields.io/opencollective/all/kettle-dev?style=for-the-badge\n[🖇osc-sponsors-bottom-img]: https://img.shields.io/opencollective/sponsors/kettle-dev?style=for-the-badge\n[🖇osc-backers-bottom-img]: https://img.shields.io/opencollective/backers/kettle-dev?style=for-the-badge\n[🖇osc]: https://opencollective.com/kettle-dev\n[🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social\u0026logo=github\n[🖇sponsor-bottom-img]: https://img.shields.io/badge/Sponsor_Me!-pboling-blue?style=for-the-badge\u0026logo=github\n[🖇sponsor]: https://github.com/sponsors/pboling\n[🖇polar-img]: https://img.shields.io/badge/polar-donate-a51611.svg?style=flat\n[🖇polar]: https://polar.sh/pboling\n[🖇kofi-img]: https://img.shields.io/badge/ko--fi-%E2%9C%93-a51611.svg?style=flat\n[🖇kofi]: https://ko-fi.com/pboling\n[🖇patreon-img]: https://img.shields.io/badge/patreon-donate-a51611.svg?style=flat\n[🖇patreon]: https://patreon.com/galtzo\n[🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-%E2%9C%93-a51611.svg?style=flat\n[🖇buyme-img]: https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20latte\u0026emoji=\u0026slug=pboling\u0026button_colour=FFDD00\u0026font_colour=000000\u0026font_family=Cookie\u0026outline_colour=000000\u0026coffee_colour=ffffff\n[🖇buyme]: https://www.buymeacoffee.com/pboling\n[🖇paypal-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat\u0026logo=paypal\n[🖇paypal-bottom-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=for-the-badge\u0026logo=paypal\u0026color=0A0A0A\n[🖇paypal]: https://www.paypal.com/paypalme/peterboling\n[🖇floss-funding.dev]: https://floss-funding.dev\n[🖇floss-funding-gem]: https://github.com/galtzo-floss/floss_funding\n[✉️discord-invite]: https://discord.gg/3qme4XHNKN\n[✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge\u0026logo=discord\n[✉️ruby-friends-img]: https://img.shields.io/badge/daily.dev-%F0%9F%92%8E_Ruby_Friends-0A0A0A?style=for-the-badge\u0026logo=dailydotdev\u0026logoColor=white\n[✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends\n\n[✇bundle-group-pattern]: https://gist.github.com/pboling/4564780\n[⛳️gem-namespace]: https://github.com/kettle-dev/kettle-dev\n[⛳️namespace-img]: https://img.shields.io/badge/namespace-Kettle::Dev-3C2D2D.svg?style=square\u0026logo=ruby\u0026logoColor=white\n[⛳️gem-name]: https://bestgems.org/gems/kettle-dev\n[⛳️name-img]: https://img.shields.io/badge/name-kettle--dev-3C2D2D.svg?style=square\u0026logo=rubygems\u0026logoColor=red\n[⛳️tag-img]: https://img.shields.io/github/tag/kettle-dev/kettle-dev.svg\n[⛳️tag]: https://github.com/kettle-dev/kettle-dev/releases\n[🚂maint-blog]: http://www.railsbling.com/tags/kettle-dev\n[🚂maint-blog-img]: https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge\u0026logo=rubyonrails\u0026logoColor=orange\n[🚂maint-contact]: http://www.railsbling.com/contact\n[🚂maint-contact-img]: https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat\u0026logo=rubyonrails\u0026logoColor=red\n[💖🖇linkedin]: http://www.linkedin.com/in/peterboling\n[💖🖇linkedin-img]: https://img.shields.io/badge/LinkedIn-Profile-0B66C2?style=flat\u0026logo=newjapanprowrestling\n[💖✌️wellfound]: https://wellfound.com/u/peter-boling\n[💖✌️wellfound-img]: https://img.shields.io/badge/peter--boling-orange?style=flat\u0026logo=wellfound\n[💖💲crunchbase]: https://www.crunchbase.com/person/peter-boling\n[💖💲crunchbase-img]: https://img.shields.io/badge/peter--boling-purple?style=flat\u0026logo=crunchbase\n[💖🐘ruby-mast]: https://ruby.social/@galtzo\n[💖🐘ruby-mast-img]: https://img.shields.io/mastodon/follow/109447111526622197?domain=https://ruby.social\u0026style=flat\u0026logo=mastodon\u0026label=Ruby%20@galtzo\n[💖🦋bluesky]: https://bsky.app/profile/galtzo.com\n[💖🦋bluesky-img]: https://img.shields.io/badge/@galtzo.com-0285FF?style=flat\u0026logo=bluesky\u0026logoColor=white\n[💖🌳linktree]: https://linktr.ee/galtzo\n[💖🌳linktree-img]: https://img.shields.io/badge/galtzo-purple?style=flat\u0026logo=linktree\n[💖💁🏼‍♂️devto]: https://dev.to/galtzo\n[💖💁🏼‍♂️devto-img]: https://img.shields.io/badge/dev.to-0A0A0A?style=flat\u0026logo=devdotto\u0026logoColor=white\n[💖💁🏼‍♂️aboutme]: https://about.me/peter.boling\n[💖💁🏼‍♂️aboutme-img]: https://img.shields.io/badge/about.me-0A0A0A?style=flat\u0026logo=aboutme\u0026logoColor=white\n[💖🧊berg]: https://codeberg.org/pboling\n[💖🐙hub]: https://github.org/pboling\n[💖🛖hut]: https://sr.ht/~galtzo/\n[💖🧪lab]: https://gitlab.com/pboling\n[👨🏼‍🏫expsup-upwork]: https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share\n[👨🏼‍🏫expsup-upwork-img]: https://img.shields.io/badge/UpWork-13544E?style=for-the-badge\u0026logo=Upwork\u0026logoColor=white\n[👨🏼‍🏫expsup-codementor]: https://www.codementor.io/peterboling?utm_source=github\u0026utm_medium=button\u0026utm_term=peterboling\u0026utm_campaign=github\n[👨🏼‍🏫expsup-codementor-img]: https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge\u0026logo=CodeMentor\u0026logoColor=white\n[🏙️entsup-tidelift]: https://tidelift.com/subscription/pkg/rubygems-kettle-dev?utm_source=rubygems-kettle-dev\u0026utm_medium=referral\u0026utm_campaign=readme\n[🏙️entsup-tidelift-img]: https://img.shields.io/badge/Tidelift_and_Sonar-Enterprise_Support-FD3456?style=for-the-badge\u0026logo=sonar\u0026logoColor=white\n[🏙️entsup-tidelift-sonar]: https://blog.tidelift.com/tidelift-joins-sonar\n[💁🏼‍♂️peterboling]: http://www.peterboling.com\n[🚂railsbling]: http://www.railsbling.com\n[📜src-gl-img]: https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge\u0026logo=Gitlab\u0026logoColor=orange\n[📜src-gl]: https://gitlab.com/kettle-dev/kettle-dev\n[📜src-cb-img]: https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge\u0026logo=CodeBerg\u0026logoColor=blue\n[📜src-cb]: https://codeberg.org/kettle-dev/kettle-dev\n[📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge\u0026logo=Github\u0026logoColor=green\n[📜src-gh]: https://github.com/kettle-dev/kettle-dev\n[📜docs-cr-rd-img]: https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge\u0026logo=readthedocs\u0026logoColor=white\n[📜docs-head-rd-img]: https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge\u0026logo=readthedocs\u0026logoColor=white\n[📜gl-wiki]: https://gitlab.com/kettle-dev/kettle-dev/-/wikis/home\n[📜gh-wiki]: https://github.com/kettle-dev/kettle-dev/wiki\n[📜gl-wiki-img]: https://img.shields.io/badge/wiki-gitlab-943CD2.svg?style=for-the-badge\u0026logo=gitlab\u0026logoColor=white\n[📜gh-wiki-img]: https://img.shields.io/badge/wiki-github-943CD2.svg?style=for-the-badge\u0026logo=github\u0026logoColor=white\n[👽dl-rank]: https://bestgems.org/gems/kettle-dev\n[👽dl-ranki]: https://img.shields.io/gem/rd/kettle-dev.svg\n[👽version]: https://bestgems.org/gems/kettle-dev\n[👽versioni]: https://img.shields.io/gem/v/kettle-dev.svg\n[🏀qlty-mnt]: https://qlty.sh/gh/kettle-dev/projects/kettle-dev\n[🏀qlty-mnti]: https://qlty.sh/gh/kettle-dev/projects/kettle-dev/maintainability.svg\n[🏀qlty-cov]: https://qlty.sh/gh/kettle-dev/projects/kettle-dev/metrics/code?sort=coverageRating\n[🏀qlty-covi]: https://qlty.sh/gh/kettle-dev/projects/kettle-dev/coverage.svg\n[🏀codecov]: https://codecov.io/gh/kettle-dev/kettle-dev\n[🏀codecovi]: https://codecov.io/gh/kettle-dev/kettle-dev/graph/badge.svg\n[🏀coveralls]: https://coveralls.io/github/kettle-dev/kettle-dev?branch=main\n[🏀coveralls-img]: https://coveralls.io/repos/github/kettle-dev/kettle-dev/badge.svg?branch=main\n[🚎ruby-2.4-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/ruby-2.4.yml\n[🚎ruby-2.5-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/ruby-2.5.yml\n[🚎ruby-2.6-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/ruby-2.6.yml\n[🚎ruby-2.7-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/ruby-2.7.yml\n[🚎ruby-3.0-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/ruby-3.0.yml\n[🚎ruby-3.1-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/ruby-3.1.yml\n[🚎ruby-3.2-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/ruby-3.2.yml\n[🚎ruby-3.3-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/ruby-3.3.yml\n[🚎ruby-3.4-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/ruby-3.4.yml\n[🚎jruby-9.2-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/jruby-9.2.yml\n[🚎jruby-9.3-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/jruby-9.3.yml\n[🚎jruby-9.4-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/jruby-9.4.yml\n[🚎truby-22.3-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/truffleruby-22.3.yml\n[🚎truby-23.0-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/truffleruby-23.0.yml\n[🚎truby-23.1-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/truffleruby-23.1.yml\n[🚎truby-24.2-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/truffleruby-24.2.yml\n[🚎truby-25.0-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/truffleruby-25.0.yml\n[🚎2-cov-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/coverage.yml\n[🚎2-cov-wfi]: https://github.com/kettle-dev/kettle-dev/actions/workflows/coverage.yml/badge.svg\n[🚎3-hd-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/heads.yml\n[🚎3-hd-wfi]: https://github.com/kettle-dev/kettle-dev/actions/workflows/heads.yml/badge.svg\n[🚎5-st-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/style.yml\n[🚎5-st-wfi]: https://github.com/kettle-dev/kettle-dev/actions/workflows/style.yml/badge.svg\n[🚎9-t-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/truffle.yml\n[🚎9-t-wfi]: https://github.com/kettle-dev/kettle-dev/actions/workflows/truffle.yml/badge.svg\n[🚎10-j-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/jruby.yml\n[🚎10-j-wfi]: https://github.com/kettle-dev/kettle-dev/actions/workflows/jruby.yml/badge.svg\n[🚎11-c-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/current.yml\n[🚎11-c-wfi]: https://github.com/kettle-dev/kettle-dev/actions/workflows/current.yml/badge.svg\n[🚎12-crh-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/dep-heads.yml\n[🚎12-crh-wfi]: https://github.com/kettle-dev/kettle-dev/actions/workflows/dep-heads.yml/badge.svg\n[🚎13-🔒️-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/locked_deps.yml\n[🚎13-🔒️-wfi]: https://github.com/kettle-dev/kettle-dev/actions/workflows/locked_deps.yml/badge.svg\n[🚎14-🔓️-wf]: https://github.com/kettle-dev/kettle-dev/actions/workflows/unlocked_deps.yml\n[🚎14-🔓️-wfi]: https://github.com/kettle-dev/kettle-dev/actions/workflows/unlocked_deps.yml/badge.svg\n[💎ruby-2.4i]: https://img.shields.io/badge/Ruby-2.4-DF00CA?style=for-the-badge\u0026logo=ruby\u0026logoColor=white\n[💎ruby-2.5i]: https://img.shields.io/badge/Ruby-2.5-DF00CA?style=for-the-badge\u0026logo=ruby\u0026logoColor=white\n[💎ruby-2.6i]: https://img.shields.io/badge/Ruby-2.6-DF00CA?style=for-the-badge\u0026logo=ruby\u0026logoColor=white\n[💎ruby-2.7i]: https://img.shields.io/badge/Ruby-2.7-DF00CA?style=for-the-badge\u0026logo=ruby\u0026logoColor=white\n[💎ruby-3.0i]: https://img.shields.io/badge/Ruby-3.0-CC342D?style=for-the-badge\u0026logo=ruby\u0026logoColor=white\n[💎ruby-3.1i]: https://img.shields.io/badge/Ruby-3.1-CC342D?style=for-the-badge\u0026logo=ruby\u0026logoColor=white\n[💎ruby-3.2i]: https://img.shields.io/badge/Ruby-3.2-CC342D?style=for-the-badge\u0026logo=ruby\u0026logoColor=white\n[💎ruby-3.3i]: https://img.shields.io/badge/Ruby-3.3-CC342D?style=for-the-badge\u0026logo=ruby\u0026logoColor=white\n[💎ruby-3.4i]: https://img.shields.io/badge/Ruby-3.4-CC342D?style=for-the-badge\u0026logo=ruby\u0026logoColor=white\n[💎ruby-4.0i]: https://img.shields.io/badge/Ruby-4.0-CC342D?style=for-the-badge\u0026logo=ruby\u0026logoColor=white\n[💎ruby-c-i]: https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge\u0026logo=ruby\u0026logoColor=green\n[💎ruby-headi]: https://img.shields.io/badge/Ruby-HEAD-CC342D?style=for-the-badge\u0026logo=ruby\u0026logoColor=blue\n[💎truby-22.3i]: https://img.shields.io/badge/Truffle_Ruby-22.3-34BCB1?style=for-the-badge\u0026logo=ruby\u0026logoColor=pink\n[💎truby-23.0i]: https://img.shields.io/badge/Truffle_Ruby-23.0-34BCB1?style=for-the-badge\u0026logo=ruby\u0026logoColor=pink\n[💎truby-23.1i]: https://img.shields.io/badge/Truffle_Ruby-23.1-34BCB1?style=for-the-badge\u0026logo=ruby\u0026logoColor=pink\n[💎truby-24.2i]: https://img.shields.io/badge/Truffle_Ruby-24.2-34BCB1?style=for-the-badge\u0026logo=ruby\u0026logoColor=pink\n[💎truby-25.0i]: https://img.shields.io/badge/Truffle_Ruby-25.0-34BCB1?style=for-the-badge\u0026logo=ruby\u0026logoColor=pink\n[💎truby-c-i]: https://img.shields.io/badge/Truffle_Ruby-current-34BCB1?style=for-the-badge\u0026logo=ruby\u0026logoColor=green\n[💎jruby-9.2i]: https://img.shields.io/badge/JRuby-9.2-FBE742?style=for-the-badge\u0026logo=ruby\u0026logoColor=red\n[💎jruby-9.3i]: https://img.shields.io/badge/JRuby-9.3-FBE742?style=for-the-badge\u0026logo=ruby\u0026logoColor=red\n[💎jruby-9.4i]: https://img.shields.io/badge/JRuby-9.4-FBE742?style=for-the-badge\u0026logo=ruby\u0026logoColor=red\n[💎jruby-c-i]: https://img.shields.io/badge/JRuby-current-FBE742?style=for-the-badge\u0026logo=ruby\u0026logoColor=green\n[💎jruby-headi]: https://img.shields.io/badge/JRuby-HEAD-FBE742?style=for-the-badge\u0026logo=ruby\u0026logoColor=blue\n[🤝gh-issues]: https://github.com/kettle-dev/kettle-dev/issues\n[🤝gh-pulls]: https://github.com/kettle-dev/kettle-dev/pulls\n[🤝gl-issues]: https://gitlab.com/kettle-dev/kettle-dev/-/issues\n[🤝gl-pulls]: https://gitlab.com/kettle-dev/kettle-dev/-/merge_requests\n[🤝cb-issues]: https://codeberg.org/kettle-dev/kettle-dev/issues\n[🤝cb-pulls]: https://codeberg.org/kettle-dev/kettle-dev/pulls\n[🤝cb-donate]: https://donate.codeberg.org/\n[🤝contributing]: https://github.com/kettle-dev/kettle-dev/blob/main/CONTRIBUTING.md\n[🏀codecov-g]: https://codecov.io/gh/kettle-dev/kettle-dev/graph/badge.svg\n[🖐contrib-rocks]: https://contrib.rocks\n[🖐contributors]: https://github.com/kettle-dev/kettle-dev/graphs/contributors\n[🖐contributors-img]: https://contrib.rocks/image?repo=kettle-dev/kettle-dev\n[🚎contributors-gl]: https://gitlab.com/kettle-dev/kettle-dev/-/graphs/main\n[🪇conduct]: https://github.com/kettle-dev/kettle-dev/blob/main/CODE_OF_CONDUCT.md\n[🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg\n[📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint\n[📌semver]: https://semver.org/spec/v2.0.0.html\n[📌semver-img]: https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat\n[📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139\n[📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html\n[📌changelog]: https://github.com/kettle-dev/kettle-dev/blob/main/CHANGELOG.md\n[📗keep-changelog]: https://keepachangelog.com/en/1.0.0/\n[📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat\n[📌gitmoji]: https://gitmoji.dev\n[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square\n[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ\n[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.100-FFDD67.svg?style=for-the-badge\u0026logo=YouTube\u0026logoColor=blue\n[🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md\n[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat\n[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year\n[📄license]: LICENSE.md\n[📄license-ref]: AGPL-3.0-only.md\n[📄license-img]: https://img.shields.io/badge/License-AGPL--3.0--only-259D6C.svg\n[📄license-compat]: https://www.apache.org/legal/resolved.html#category-x\n[📄license-compat-img]: https://img.shields.io/badge/Apache_Incompatible:_Category_X-%E2%9C%97-C0392B.svg?style=flat\u0026logo=Apache\n\n[📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm\n[📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat\n[🚎yard-current]: http://rubydoc.info/gems/kettle-dev\n[🚎yard-head]: https://kettle-dev.galtzo.com\n[💎stone_checksums]: https://github.com/galtzo-floss/stone_checksums\n[💎SHA_checksums]: https://gitlab.com/kettle-dev/kettle-dev/-/tree/main/checksums\n[💎rlts]: https://github.com/rubocop-lts/rubocop-lts\n[💎rlts-img]: https://img.shields.io/badge/code_style_\u0026_linting-rubocop--lts-34495e.svg?plastic\u0026logo=ruby\u0026logoColor=white\n[💎appraisal2]: https://github.com/appraisal-rb/appraisal2\n[💎appraisal2-img]: https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic\u0026logo=ruby\u0026logoColor=white\n[💎d-in-dvcs]: https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/\n\n\u003c!-- kettle-jem:metadata:start --\u003e\n| Field | Value |\n|---|---|\n| Package | kettle-dev |\n| Description | 🍲 Kettle::Dev is a meta tool from kettle-rb to streamline development and testing. Acts as a shim dependency, pulling in many other dependencies, to give you OOTB productivity with a RubyGem, or Ruby app project. Configures a complete set of Rake tasks, for all the libraries is brings in, so they arrive ready to go. Fund overlooked open source projects - bottom of stack, dev/test dependencies: floss-funding.dev |\n| Homepage | https://github.com/kettle-dev/kettle-dev |\n| Source | https://github.com/kettle-dev/kettle-dev/tree/v2.2.1 |\n| License | `AGPL-3.0-only` |\n| Funding | https://github.com/sponsors/pboling, https://issuehunt.io/u/pboling, https://ko-fi.com/pboling, https://liberapay.com/pboling/donate, https://opencollective.com/kettle-dev, https://opencollective.com/kettle-rb, https://patreon.com/galtzo, https://polar.sh/pboling, https://thanks.dev/u/gh/pboling, https://tidelift.com/funding/github/rubygems/kettle-dev, https://www.buymeacoffee.com/pboling |\n\u003c!-- kettle-jem:metadata:end --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkettle-dev%2Fkettle-dev","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkettle-dev%2Fkettle-dev","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkettle-dev%2Fkettle-dev/lists"}