The Lab · Development
The Version Number Every RAXXO Tool Follows and Why
Every RAXXO tool follows strict semantic versioning, and the one time I fudged a patch release cost me a support thread I could have avoided.
Each line jumps to its section
- Every RAXXO tool ships under strict semantic versioning, major.minor.patch, and I never break that pattern even for a tiny fix
- A patch bump means nothing changed except a bug going away, a minor bump means something new showed up without breaking anything old, a major bump is a promise I rarely make
- The one time I skipped the discipline, a silent breaking change went out labeled as a patch and it cost me a support thread I could have avoided entirely
- The changelog and the version number are the same commitment written twice, and skipping either one breaks trust faster than any bug does
Why a Solo Studio Even Needs This
It would be easy to assume version numbers matter for teams, not for one person shipping small tools. I thought that too, before I had five live products and a support inbox that made it obvious how wrong that assumption was. A customer who bought a RAXXO tool eight months ago and only opens it twice a year has no idea what changed in between. The version number is the only honest answer I can give them without writing a personal message to every single user, and it has to be an answer that means the same thing every time.
Semantic versioning gives me that consistency for free, as long as I actually follow it instead of treating it as decoration. The rule is simple to state: a patch release changes nothing except fixing something broken, a minor release adds capability without removing or altering anything that already worked, and a major release is allowed to break things, on purpose, with warning. The value is not in the rule itself, plenty of solo developers know the rule. The value is in never being tempted to shortcut it because a change feels small in the moment.
I've written before about the changelog habit that keeps every RAXXO tool honest, and version numbers are the other half of that same commitment. A changelog entry without a version number attached to it is just a diary. A version number without a changelog entry explaining it is just a number nobody can use. They only work as a pair, and I treat a release as unfinished until both exist for it.
There is also a quieter reason this matters to me specifically, separate from any individual customer. Running several tools alone means I am constantly context switching between codebases that have not been open on my screen in weeks. A strict version scheme is a memory aid as much as it is a promise to users. When I open an old tool's repository and see it sitting at version 2.4.1, I immediately know something about its history before I read a single line of the changelog, that it has shipped one breaking change since launch and has been stable enough since then to only need small additions and fixes. That context takes seconds to reconstruct from a well kept version number and much longer to reconstruct by reading commit history cold.
The Discipline of Never Fudging a Patch
The failure mode I watch for most closely is the one where a patch release quietly does more than fix a bug. It happens innocently. I am already in the code fixing one thing, I notice something else nearby that could be better, and it is tempting to bundle a small improvement into the same release since I am already touching that file. I no longer allow myself to do this, because "small improvement" and "no behavior changed" are not the same claim, and a patch version is a specific promise that only the second one is true.
The test I apply before tagging anything as a patch is blunt: could a user who has automation built around this tool's current behavior update to this version and have that automation silently do something different. If the honest answer is maybe, it is not a patch, no matter how minor the change looks in a diff. This matters more for the RAXXO tools with an API or a scriptable interface than for a purely visual product, because those are exactly the tools where someone else's code is quietly depending on today's exact behavior continuing tomorrow.
Minor releases get more room, but not unlimited room. Adding a new setting, a new export option, a new view, all of that is fair game for a minor bump as long as the tool behaves exactly as it did before for anyone who ignores the new capability entirely. The moment a new feature changes a default, or changes what happens when someone does nothing differently than before, that additive promise is broken and the change belongs in a major release instead, however tempting it is to call it minor because it "only affects new users."
I apply the same test to dependency updates, which is a category people forget counts at all. Bumping a library underneath a RAXXO tool can absolutely be a patch, if I have checked that nothing it touches changes observable behavior. But I have caught myself, more than once, wanting to fold in a library upgrade "while I'm in there" on a release that should have stayed a pure bug fix, purely because the upgrade felt like housekeeping rather than a real change. Housekeeping that can alter output, timing, or error behavior is not exempt from the rule just because it did not originate in my own code. If anything it deserves more scrutiny, since it is the kind of change I am least likely to have fully tested myself.
It is worth being honest about the limits of this discipline too, because a version number only carries the weight I put into it. Semantic versioning says nothing about how urgent a release is, how severe the bug it fixes was, or whether a minor release happens to include something a particular user has been waiting months for. The version number tells you the shape of the risk in updating, not the size of the benefit, and conflating those two is its own small failure mode I try to avoid when I write release notes. I have also learned not to lean on the number as a substitute for actually testing a release before it goes out. A correctly labeled patch that still has a bug in it is still a bug, and calling it a patch does not make the mistake smaller for the person who hits it.
The Time I Broke My Own Rule
I try to write these posts around a real mistake rather than a hypothetical one, and this rule has exactly one violation on record. An early RAXXO tool needed a fix for a formatting bug, a genuinely small change, three lines. While I was in there I also adjusted how the tool handled a particular edge case in its input, because the old behavior looked clearly wrong to me and the new behavior looked clearly better. I tagged the whole thing as a patch and shipped it without a second thought, because in my head I was still fixing one bug.
A handful of users had built their own small scripts around the old edge case behavior, the one I was so sure was simply wrong. It was not wrong for their use case, it was just unusual, and my patch broke every one of those scripts without warning, because nothing about a patch version told them to expect a behavior change. The support thread that followed was not hostile, but it was clear, and it was entirely earned. I had made a major-scale promise, "this update changes how the tool behaves," and shipped it wearing a patch's label, which told every one of those users the opposite was true.
The fix afterward was straightforward, a follow-up release that reverted the edge case change and reintroduced it properly in a minor version with a changelog note calling it out by name. The lesson that stuck was less about the specific bug and more about the discipline itself. The three lines of formatting fix were never the risky part of that release. The unrelated edge case tweak riding along inside a version number that promised it would not be there was the actual mistake, and it is the only kind of mistake this rule exists to prevent.
What Actually Changed in My Workflow After That
The practical change was small and has held up for every release since. Before I tag anything, I write the version bump decision down in one sentence before I write the changelog entry, not after. Something like "patch, formatting fix only, no behavior change anywhere else" or "minor, new export format added, nothing else touched." Writing that sentence first forces me to notice when a release does not fit the label I am about to give it, because the sentence gets awkward to write honestly the moment I am stretching the truth.
The second change was refusing to bundle unrelated work into one release just because both changes happened to be ready around the same time. If a bug fix and a new feature are both done, they ship as two releases, a patch and then a minor, even if that means tagging and shipping twice in the same afternoon. It costs me a few extra minutes of process. It buys back the ability for anyone reading a changelog to know exactly what kind of risk they are taking by updating, which is the entire point of having version numbers instead of just a running list of changes.
I also stopped treating major version bumps as something to avoid out of embarrassment. Early on I quietly folded breaking changes into what should have been major releases because bumping that first number felt like admitting the tool was not stable yet. That instinct has it backwards. A major version bump that is honest about breaking something is far more trustworthy than a minor or patch release that hides the same break behind a smaller number. Users forgive a clearly labeled breaking change they can prepare for. They do not forgive one they discover by accident. This is the same judgment call I described in how I decide a RAXXO tool needs a redesign, not a patch: naming a change honestly, even when the honest label is the less flattering one, is what keeps the whole system trustworthy.
Bottom Line
None of this is complicated once it is written down, which is exactly why it is easy to let slip under deadline pressure. Semantic versioning only works if every single release respects what its own number promises, and the discipline required is not technical, it is just refusing to shortcut the label because a change feels small to the person shipping it rather than to the person receiving it.
The one violation I have on record cost me a support thread and a follow-up release, which is a mild price for the lesson, and I would rather write about that mistake here than repeat a version of it on a bigger tool with more users depending on the old behavior. A version number is a small, quiet promise attached to every release a RAXXO tool ever ships, and it turns out to be one of the easiest promises to keep once I stopped treating small exceptions as harmless.