CLI tool
toolkit-for-ynab/toolkit-for-ynab avatar
toolkit-for-ynab/toolkit-for-ynab

Toolkit for YNAB: maintenance mode, a release script that opens its own pull request, and a build that generates indexes twice

A general purpose YNAB enhancing browser extension for Chrome and Firefox. Have it your way!

1,517 stars360 forksTypeScriptMIT

At a glance

What is it?
Toolkit for YNAB is a Web Extensions build for Chrome, Firefox and Edge that adds features to the YNAB budgeting web app. Its own README declares maintenance mode and asks for maintainers, while package.json shows the release duty is one gh pr create command and the production chain has no manifest step for Chrome.
Who is it for?
Judgement for anyone budgeting in a browser: keep this extension if it already earns its place in your workflow, because the 2026-09-09 push and release v3.23.0 show fixes still land, but plan for no new features while the project is in maintenance mode. Do not wait on a Safari or iOS build.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 14 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • toolkit-for-ynab/toolkit-for-ynab1,517 ★ · +5
Star history
Repository2026-08-042026-11-14
toolkit-for-ynab/toolkit-for-ynab1.5k1.5k

5 Stars in the last 102 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The maintenance banner sits on top of a release from three weeks ago

The README opens with a heading reading Maintenance Mode (Looking for Maintainers). The paragraph under it says the project is officially in maintenance mode, that updates will be far less frequent than before, and that they will be limited to bug fixes rather than new features. It asks for new maintainers willing to take on the duties of approving and releasing updates, and names Josh Madewell on the project Discord as the person to reach.

The repository record does not contradict that banner, but it adds context the banner leaves out. The repository is not archived, the last push is dated 2026-09-09, and that same day carries release v3.23.0, which follows v3.22.5 on 2026-08-04 and v3.22.4 on 2026-07-28. Three tagged releases in about six weeks is not the shape of a stopped project. What the notice describes is a change in who reviews work and how often it ships, not a freeze on the code. The default branch is develop, so commits continue to land there while releases travel a separate route to main.

The reason the project exists is stated just under the banner. YNAB shipped a new web version, power users of the older ones wanted options that a browser extension could implement easily, and the answer the project picked was to build them itself rather than ask the YNAB team to add them. That framing also explains the risk in maintenance mode: the feature list is the value, and new features are the part now on hold.

Releases are a pull request the maintainer opens for themselves

Nothing is pushed and tagged by hand. The release script in package.json is a single line:

code
"release": "git fetch origin && git checkout develop && git pull origin develop && gh pr create --base main --title 'chore(release): merge develop into main' --body ''"

It fetches, switches to develop, pulls it, then opens a pull request from develop into main with an empty description body. Whoever runs it needs the GitHub CLI authenticated and permission to open a pull request against main. That is exactly the duty the maintenance notice is recruiting for, and the script only covers the second half of it: nothing in this line approves anything, it just moves merged work from one branch to another.

The beta channel is built the same way around. deploy:beta is git fetch origin main:beta && git push origin beta, which republishes whatever main already contains under a beta ref instead of shipping an unmerged branch, and build:beta pairs the beta webpack target with the beta manifest override before compressing.

Chrome is the only packaged target with no manifest override

The production chain in package.json reads:

code
"build:production": "yarn build:check && yarn webpack:production && yarn compress:chrome && yarn manifest:firefox && yarn compress:firefox"

Read left to right, it compresses Chrome, then applies the Firefox manifest override, then compresses Firefox. Every other packaged target has a manifest override of its own: manifest:beta, manifest:development, manifest:ios and manifest:firefox each run ts-node scripts/applyManifestOverrides.ts with a different type value. Among that group no chrome variant appears, so Chrome is the one store build that goes out with no override applied, even though the install section lists the Chrome Web Store first.

Each compress step runs two scripts rather than one. compress:chrome is ts-node scripts/compressSrc.ts --browser=chrome followed by ts-node scripts/compressDist.ts --browser=chrome, and compress:firefox repeats that pair with the firefox value. One production build therefore rewrites the source tree twice, once per browser, before it touches the distribution bundles.

An iOS build target that the install notes never account for

package.json carries a target the installation documentation never mentions:

code
"build:ios": "yarn build:check && yarn webpack:production && yarn manifest:ios"

The install section points the other way on Apple platforms. It says the extension is built using Browser (Web) Extension APIs, that Web Extensions is not supported by Safari, that the extension itself is therefore not supported on Safari, and that support would follow only if Safari decides to support Web Extensions. Nothing in the visible text explains what the ios type changes in the manifest or which store it would reach.

The chain also stops earlier than its siblings. build:ios ends at the manifest override, with no compress step and no compress:ios script anywhere alongside the firefox and chrome ones. Two Apple facts sit side by side without meeting: a documented statement that Safari is out of scope, and a shipped build target plus override named for iOS. Reading scripts/applyManifestOverrides.ts settles what the ios type actually rewrites.

Yarn 1 build steps next to a .yarnrc.yml at the repository root

Step two of the build asks for Node.js (>=18.12.1) and Yarn (>= v1.10.0), installed through brew on macOS, where xcode-select --install is also required, or through Chocolatey on Windows. The root of the repository carries .nvmrc, .yarnrc.yml, a .yarn directory and yarn.lock. The Firefox deployment steps then lean on subcommands from that same older Yarn line:

code
$ yarn global add web-ext
code
$ PATH=$PATH:$(yarn global bin)

The second one is meant to sit in ~/.bash_profile so that web-ext lands on PATH. Check which Yarn the .yarnrc.yml you checked out is written for before following either step, since the documented install path and the config files next to it do not obviously describe one toolchain.

Install also has a side effect. The prepare script runs husky install, and a .husky directory sits at the root, so git hooks get wired up as part of yarn install rather than as a separate step.

Two shortcuts sit alongside those steps. A .nvmrc file pins a Node version that the written instructions never mention, and the install steps are numbered so that a VS Code user can run a Setup task instead and skip the install and build lines altogether, which is why a .vscode directory is committed.

Every check regenerates indexes, and CI does it twice

build:check is yarn && yarn gen, and it is the first link in build:beta, build:development, build:production and build:ios, so index generation runs at the head of nearly every build. The CI script then runs it a second time:

code
"build:ci": "yarn gen && yarn sentry:create && yarn build:production && yarn sentry:upload"

build:ci calls yarn gen, then calls build:production, which opens with build:check, which calls yarn and yarn gen again. The two watch scripts exist because of that same cost. yarn watch monitors the project directory and re-runs build:development on every change, regenerating indexes each time. yarn watch:webpack compiles only the code that changed, without regenerating indexes, which the build notes say might noticeably speed up development when a change does not need new indexes. Contributors adding features rather than editing existing ones are pointed at the first path, which is the slow one.

The legal section stops one clause into its first sentence

The last heading in the README is Legal Stuff, and the line beneath it begins IMPORTANT NOTE: This extension is and then ends. The clause about what the extension is and is not allowed to do with YNAB's name and its data is the part that is not there, so the licensing relationship between this extension and somebody else's budgeting product has to be read in the file rather than taken from a summary. A privacy-policy.md sits at the repository root for the same reason.

The build pipeline has a data path of its own. build:ci runs sentry:create before build:production and sentry:upload after it, so every CI build prepares and ships source maps to an external error service. For an extension whose whole job is drawing a household budget inside somebody else's page, that puts a third party in the loop, and the two files to read before installing are privacy-policy.md and the scripts that decide what sentry:upload sends.

A style vote left a .git-blame-ignore-revs file behind

Feature work is meant to begin in one directory. The build notes point developers at src/extension/features, where subdirectories correspond to sections of the YNAB application and where the replacement framework lives. The stated reason for that framework is boilerplate: the old one required every feature to carry a large amount of it, and the new one leans on ES6 syntax to cut that burden. Babel transpiles ES2015 back to ES5, and webpack bundles the background, popup, options and content script entry points into single files. Feature switches live on the options page, with the full list kept in docs/feature-list.md.

Style enforcement is unusually visible for a project this size. Contributors are told a team vote settled on the AirBNB style guide after the codebase had drifted, ESLint is named as one of three build tools, and the root carries .eslintrc, .eslintignore, .prettierrc, .prettierignore, .editorconfig and .gitattributes. It also carries .git-blame-ignore-revs, the file used to hide commits from blame, which is the residue of exactly that kind of repository-wide reformat. One documented build failure belongs to the same territory: editors must be set to Unix line feeds or the build fails, a warning aimed mostly at contributors on Windows.

The rest of the root shows how much of the process is automated around those rules: a checks directory, a main.yml, a scripts directory holding the manifest and compression helpers, a .github_changelog_generator directory, and both CLAUDE.md and a .claude directory for tooling instructions. Contributor guidance for building a feature lives in docs/building-features.md rather than in the README itself.

Editorial conclusion

Judgement for anyone budgeting in a browser: keep this extension if it already earns its place in your workflow, because the 2026-09-09 push and release v3.23.0 show fixes still land, but plan for no new features while the project is in maintenance mode. Do not wait on a Safari or iOS build. Before installing, read privacy-policy.md and the unfinished legal note at the end of the README, and confirm which Yarn your checkout expects, because the documented yarn global add web-ext step and the .yarnrc.yml sitting at the root are not obviously the same toolchain.

Frequently asked questions

Is there a toolkit for YNAB for Firefox?

Yes, published through the Firefox Add-on Repository, and buildable from source with the same Web Extensions bundle the other browsers use. The local Firefox path is yarn run manifest:firefox followed by web-ext run --source-dir dist/extension/. Safari is a separate story: Web Extensions is not supported there, so the extension is not.

Does Toolkit for YNAB work in Safari or on iOS?

The install notes rule Safari out because Web Extensions is not supported by that browser, yet package.json defines build:ios and manifest:ios. Nothing visible explains what the ios manifest type changes, so treat the iOS target as unverified until you read scripts/applyManifestOverrides.ts.

How do I build Toolkit for YNAB from source?

Clone the repository, install Node.js (>=18.12.1) and Yarn (>= v1.10.0), then run yarn install followed by yarn build:development. Output lands in the dist/extension folder, which is what chrome://extensions loads as an unpacked extension. Editors must use Unix line feeds or the build fails.

Who ships Toolkit for YNAB releases now?

The project asks for new maintainers to take over approving and releasing updates, and names Josh Madewell on its Discord as the contact. The release script opens a pull request from develop into main, so the recruiting is for the approval half of the job as much as the button press.

Official sources

  1. Official README
  2. Project repository
  3. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/toolkit-for-ynab-toolkit-for-ynab.svg)](https://hysenlabs.com/projects/toolkit-for-ynab-toolkit-for-ynab)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/toolkit-for-ynab-toolkit-for-ynab.svg)](https://hysenlabs.com/projects/toolkit-for-ynab-toolkit-for-ynab)

Was this useful?