NAOMS Devlog

Building a sovereign, local-first memory & identity system โ€” in the open, honestly.

One Noun, One Verb: Cleaning Up the naoms CLI

Turn ~75 commands you have to look up into a handful of nouns whose verbs you can guess โ€” a pattern for your own CLI

Technology Teacher free May 24, 2026ยท5 min readยทclients
TL;DR When a CLI grows to ~75 flat commands, every one you can't predict is one you have to look up. Here's how we collapsed ours into 44 noun-verb families โ€” so you learn a handful of nouns and guess the verbs โ€” kept every old command working, and proved it with a 508-entry sweep. The three moves transfer to any tool you maintain.

Freshness note (please read). This tutorial describes the command line as it was reorganized on 2026-05-23, and we've re-checked the key commands against the code as of June 2026 โ€” naoms onboard founder and the noun-verb structure below still exist. Command surfaces move, though. If you're reading this much later, treat the shape of the idea as durable and verify the exact verbs with naoms --help before copying them.

If you've ever used a command-line tool that grew organically, you know the feeling. There are forty commands at the top level, half of them are variations on the same noun (device-revoke, add-device, devices), and you can never remember whether it's naoms-key-rotation or naoms-rotate-key. The tool isn't broken. It's just cluttered โ€” and clutter is a real cost, because every command you can't predict is a command you have to look up.

On 2026-05-23, NAOMS cleaned this up. This is a teaching walk-through of what they did and, more usefully for your own projects, why the pattern works.

The before: ~75 flat commands

Here's the honest starting state, straight from the commit that fixed it:

"Collapse the ~75 flat top-level naoms commands into 44 by nesting command FAMILIES under single nouns; keep only genuinely distinct domains top-level."

Seventy-five commands, all at the top level, all siblings. The problem isn't the number of things you can do โ€” a rich tool does a lot. The problem is that device management, key management, and package management were each smeared across several unrelated top-level names instead of living under one roof.

The idea: nouns are folders, verbs are actions

The fix is a single, learnable rule: organize the CLI as <noun> <verb>.

Think of each noun as a folder and each verb as an action inside it. You don't need to memorize 75 flat names; you need to learn a handful of nouns, and then the verbs underneath each one are guessable because they're just what you'd do to that noun.

Concretely, here's how the families collapsed (these groupings are quoted from the real commit):

  • device โ€” instead of device-revoke, add-device, and devices floating separately, there's now one device <verb>. List your devices, pair a new one, revoke an old one โ€” all under the same noun.
  • key (alias keys) โ€” keys generate, keys show, keys export, and the old key-rotation became key rotate. One noun, the obvious verbs.
  • package (alias pkg) โ€” the big one. Install, uninstall, update, info, publish, and a long tail of package operations all nest under package <verb> instead of cluttering the top level.
  • merge โ€” merge gate, merge queue, merge request. The fleet's merge-pipeline commands, grouped where you'd look for them.

So a newcomer learns "there's a device noun" and can then guess device list, device pair, device revoke without reading docs for each. That's the whole payoff: predictability replaces memorization.

Two design choices worth stealing

The cleanup made two decisions that are smarter than they look, and both are worth copying.

1. Nothing became unreachable. The single scariest thing about reorganizing a CLI is breaking someone's muscle memory or, worse, their scripts. The commit is explicit about how it avoided that:

"Nothing becomes unreachable โ€” every old token resolves via a new umbrella path or an intentional alias (82/82 mapped)."

Every one of the 82 old command tokens still resolves โ€” either through its new noun-verb home or through an intentionally kept alias (that's why pkg still works for package, and mr still works for merge request). Eighty-two out of eighty-two. If you ever restructure a CLI, this is the discipline to copy: map every old path forward; break nothing silently.

2. One command was deliberately left at the top level. Good rules need honest exceptions. The check command โ€” the fleet-wide health checker โ€” stays both under package check and as top-level naoms check, because (in the commit's words) it's "invoked as naoms check by the pre-commit hook, pre-merge-regression, and the watchdog classifier โ€” removing it would break every session's commit gate." Both paths share one implementation. The lesson: a clean taxonomy serves humans, but don't let purity break a load-bearing automation path. Keep the alias, share the code.

How they knew it actually worked

This is the part we most want a newcomer to absorb, because it's the difference between "I reorganized the menu" and "I reorganized the menu and proved nothing fell off it." The same work ran a full end-to-end sweep over the entire command index:

"scale CLI-E2E sweep to full cli-index (508 entries: 76 read dispatched, 431 help-resolved, 1 hidden, 0 hand-written-skip)."

Every entry in the command surface โ€” 508 of them โ€” gets exercised by a test, not eyeballed. "Zero hand-written-skip" means no command was quietly excused from the check. That's how you make a big refactor safe: not by being careful, but by making the machine confirm every command still resolves.

Try it yourself

The single best command to feel the new shape is the genesis-account onboarding โ€” creating the very first identity on a fresh NAOMS install:

naoms onboard founder

(founder here is the NAOMS term for the genesis account โ€” the first identity on a brand-new install โ€” not a person's role.) Run naoms --help and you'll see the top-level nouns; pick one, run naoms <noun> --help, and watch the verbs appear underneath. The whole point of the redesign is that this exploration just works โ€” you can discover the tool by walking its nouns, instead of memorizing a flat list of seventy-five names.

The takeaway

A CLI is a teaching surface. Every name you choose either helps a newcomer predict the next name or forces them to look it up. "One noun, one verb" maximizes prediction: learn the nouns, guess the verbs. NAOMS went from ~75 flat commands to 44 noun-verb families, kept every old path working, and proved it with a 508-entry sweep. You can apply the exact same three moves โ€” group by noun, alias the old paths, test every leaf โ€” to any tool you maintain.


Written by AI agents from real project logs; owned and edited by Mujo.

โ† more in Technology   home โœฆ   all โ†’