Every RAXXO terminal tool follows the same verb-noun command pattern, so a command reads like an instruction instead of a puzzle
A word gets locked to one meaning across every tool, so "init" never means something different in two different products
New commands get named by asking what a stranger would type first, not by matching internal code names
The convention caught a naming collision before launch once, and that near miss is why the rule exists in writing now
Why Command Names Needed a Rule at All
The first time I shipped a second terminal-facing tool after Git Dojo, I noticed something that bothered me before I could fully explain why. Git Dojo used dojo start to begin a lesson. My new tool used run for roughly the same idea, starting a session. Both words meant the same thing to me while I was writing them. To someone using both tools in the same week, they were two different verbs for one action, learned twice for no reason.
That is a small thing on its own. One inconsistent verb across two products is not going to sink a studio. But it is the kind of small thing that compounds. A person who tries a second RAXXO tool after liking the first one is bringing muscle memory with them, whether I designed for that or not. If the muscle memory from tool one actively misleads them in tool two, I have spent their goodwill on a detail they never should have had to think about. The whole point of building more than one product under one name is that using one should make the next one easier, not harder.
So I wrote the convention down instead of trusting myself to remember it by feel. That is the actual origin story here: not a grand plan from day one, but a real inconsistency I noticed, that I then had to fix retroactively in one tool and prevent going forward in every tool after it. I renamed run to dojo start's equivalent phrasing before anyone got used to the old name, which cost me almost nothing at the time and would have cost real confusion later if I had waited.
The rule that came out of that moment is simple enough to state in one sentence: every command is a verb, followed optionally by a noun, and once a verb is claimed by a meaning in any RAXXO tool, it keeps that meaning everywhere. I did not invent this idea, plenty of well-designed CLIs follow some version of it, but writing it down as a hard rule for the studio, rather than a vague instinct, is what actually makes it stick across tools built months apart.
The Verb-Noun Pattern and Why It Beats Clever Names
Every command across every RAXXO terminal tool follows the same shape: a verb first, then an optional noun that narrows what the verb applies to. start, check, build, reset, undo. Not go, not fire, not a clever synonym that sounds nice in a demo but means nothing the first time someone reads it cold in a terminal without context.
The reasoning behind picking boring verbs over clever ones is straightforward once you say it out loud: a command name only has one job, and that job is to be guessable before you have read a single line of documentation. A command called ignite might sound more exciting than start in a pitch, but nobody who has never used the tool before is going to type ignite on instinct. They are going to type start, run, or --help, in roughly that order, and if the actual command is ignite, the tool has already made them do extra work before their first successful action.
This is where I lean hardest on a rule I first worked out while writing about the empty state every RAXXO tool needs before I call it shipped: design for the version of the user who has never seen the tool before, not the version who already knows it. A command naming convention is the same problem wearing a different hat. Once you know a tool, any command name works, because you already know what it does. The naming convention exists entirely for the version of the user who does not know yet, and that user is the only one worth designing around, because everyone eventually becomes the experienced user regardless of what the commands are called.
The noun half of the pattern does real work too. check alone is ambiguous the moment a tool has more than one thing worth checking. check config and check status read as two distinct, guessable actions instead of forcing a user to remember that plain check secretly means one specific thing. I would rather type six extra characters than make someone guess.
One Word, One Meaning, Across Every Tool
The part of the convention that takes real discipline is not picking good verbs inside a single tool. It is refusing to let the same verb mean two different things in two different tools. This is the rule that actually required the written document, because it is the one my own memory could not reliably enforce once there were more than two or three terminal tools in the lineup.
init is the clearest example. In one RAXXO tool, init sets up a fresh local project from nothing. That is the meaning init has earned across most of the terminal tooling world, and I am not interested in fighting that expectation just to be different. So init keeps that exact meaning in every RAXXO tool that has an init command at all, and if a different tool needs a command for something that is not quite that, it gets a different verb rather than reusing init for a slightly different job. The discipline is in resisting the shortcut of reaching for a familiar word because it is close enough, when close enough is exactly the kind of gap that turns into a support message six months later.
This is also where the near miss happened that actually pushed me to write the convention down as a real document instead of leaving it as an unwritten habit. While building out command names for a newer tool, I drafted sync to mean pulling remote settings down to a local machine. Another tool already used sync to mean pushing local changes up to a shared account. Same verb, close to opposite direction of data flow. I caught it during a pre-launch pass specifically because I had started keeping a running list of claimed verbs by then, checked the new command against it, and found the collision before a single user ever saw both tools in the same week. If I had shipped that collision, the failure mode is not a crash, it is someone confidently running sync in the second tool expecting the first tool's behavior, and getting the opposite of what they wanted with no error message telling them anything went wrong.
That near miss is the whole argument for treating this as a real list somewhere rather than a feeling. A feeling does not scale past two tools. A list does.
How New Commands Actually Get Named
When a new command needs a name, the process is deliberately boring. First, I write down what the command does in one plain sentence, no product language, no internal shorthand. Then I ask what a stranger, someone who has never opened any RAXXO tool before, would type if they were guessing at the command from that sentence alone. That guess is almost always the right name, and if it is not obviously right, that is usually a sign the command itself is trying to do two things at once and should probably be split into two commands instead of one oddly named one.
What does not factor into naming at all is whatever I called the thing internally while building it. Code has its own naming conventions, driven by what makes the implementation clear to me later. Command names are a completely different audience, and letting internal names leak into the command surface is one of the more common ways a CLI ends up hard to guess. A function called hydrateSessionCache internally becomes check status or reset session at the command line, never the internal name itself, because the person typing the command was never meant to know the internal name existed.
Once a name passes both of those checks, plain sentence and stranger's guess, it goes against the running list of every verb already claimed across every RAXXO tool, the same list that caught the sync collision. If the word is free, it gets claimed for that meaning permanently. If it is taken, the new command gets a different verb, even if the taken word would have technically fit fine on its own. Consistency across the whole lineup wins over the single best word for one specific tool, every time, because the lineup is the actual product a repeat user is interacting with, not any one tool in isolation.
I went through a similar exercise when I wrote about the starter template every RAXXO tool begins from, where the goal was making the first hour of building a new tool faster by reusing decisions instead of remaking them. The command naming list is the same idea applied to the part of the product a user actually types into, not the part I build from. Both exist so that decisions made once do not have to get relitigated, or worse, silently contradicted, every time a new tool ships.
Terminal-first tools like Git Dojo live or die on exactly this kind of consistency, because the terminal offers none of the visual cues a GUI would give a confused user. There is no button to hover over for a tooltip. The command name is the entire interface in that moment, and it either tells you what it does or it does not.
Bottom Line
A command naming convention sounds like the kind of detail nobody outside a studio would ever notice, and most of the time that is true, right up until it is not. The value of the rule is not that anyone praises a well-named command. It is that nobody ever has to stop and wonder what a command does, or worse, gets burned once by a word that meant something different in a tool they already trusted.
The discipline is smaller than it sounds: verb first, plain word over clever word, and one meaning locked to one word for the life of the studio's tooling. I keep a running list now instead of trusting memory, because memory already failed me once on a collision that would have quietly sent someone's data the wrong direction. Writing the rule down did not make the tools more impressive. It made them predictable, and predictable is the actual goal every time someone opens a terminal tool they have not touched in a month and still remembers exactly what to type.
Top comments (0)