Most of what talks to a service now isn’t a person. It’s a pipeline, a cron job, or an agent that read the help text thirty seconds ago and is already three commands in. A command line is the one interface all three can drive, and a well-built one is now a better way into a service than its dashboard.
So I wrote one: namecom, a command line
for name.com that covers the registrar’s full surface.
Then there is the part where it spends money. Registering a domain is a purchase, and
of everything that might invoke this, only the caller holding the keyboard hesitates
before one. An agent passes --yes because --yes makes the prompt go away. Dry runs
and confirmation prompts are things you can hand-roll per script, and things you will
get subtly wrong per script.
The flow
The whole thing is one command
domain check prints availability and a price. Then, if it checked exactly one
domain and a human is actually at the terminal, it offers to register it right there,
so there is no second command to type and no name to retype.
$ namecom domain check driftwoodco.com
DOMAIN AVAILABILITY PRICE PREMIUM
driftwoodco.com ✓ available $12.99/yr
(1 result)
Register driftwoodco.com for $12.99/yr? [y/N] y
✓ Registered driftwoodco.com (order #1180492, total $12.99)
→ Run 'namecom dns list driftwoodco.com' to add DNS records
→ Run 'namecom domain autorenew on driftwoodco.com' to enable auto-renewal
$ namecom dns create driftwoodco.com --type A --answer 1.2.3.4
✓ Created A record (id 82551037)
→ Run 'namecom dns list driftwoodco.com' to see all records
That offer has two rules worth stating. It never appears under --dry-run, because
there is no meaningful preview of an interactive purchase. And it never accepts
--yes as the answer. --yes is what you pass when you have stopped reading the
prompts, and it is the first thing an agent reaches for; honoring it here would turn a
read-only availability check into a purchase, with nothing between the two.
Install
Two lines to install
brew tap patramsey/tap
brew install namecom
There are signed release binaries for macOS, Linux and Windows if you would rather
not use Homebrew. go install works too, with one wrinkle: Go names the binary after
the module path, so it lands as namecom-cli and you will want to rename it.
Surface
Twelve groups, sixty-odd verbs
Anything the web dashboard does, with the exception of billing.
| Group | What it covers |
|---|---|
domain |
list, search, check, register, renew, lock, privacy, nameservers, contacts, transfer auth codes, pricing |
dns |
records, plus export and import in JSON or BIND zone format |
dnssec |
DS record management |
transfer |
inbound and internal transfers, eligibility, cancellation |
email url |
forwarding, both kinds |
vanity-ns |
your own branded nameservers |
auth config |
credentials and named profiles |
api |
raw authenticated passthrough, for whatever I haven’t wrapped yet |
namecom status is the one I actually run most days. It fans out across the account
and prints the portfolio in about ten lines: how many domains, what expires soon,
what transfers are still pending.
Automation
It knows when it isn’t a terminal
The default output format is a colored table when stdout is a terminal and JSON when
it is not. You never pass --output json in a pipeline. It is already JSON, because
nothing was watching. Neither does an agent, which is the case that matters more:
it would not have known to pass the flag, and it would have parsed the table.
Two separate checks drive that, which matters more than it sounds. Stdout decides the format. Stdin decides whether prompting is even possible. A command with its output redirected but a human still attached can still ask before it deletes something, and a command in CI, or inside an agent loop, never blocks on a question nobody is there to answer.
# Every domain expiring in the next 60 days
namecom domain list --output json \
| jq -r '.data[] | select(.expireDate < "2026-10-14") | .domainName'
# One name per line, straight into xargs
namecom domain list -q | xargs -I{} namecom dns create {} --type A --answer 1.2.3.4
# Show me the request you would send, then send it
namecom dns create acme.io --type TXT --answer "v=spf1 include:sendgrid.net ~all" --dry-run
--dry-run prints the request instead of sending it, and the dry run is tested
against the real one, so the preview cannot drift from what actually goes over the
wire. Credentials come from a profile, an environment variable, or a token_cmd that
shells out to your password manager and keeps the token off disk entirely.
The point
Quiet, financial, late
Say a registration goes out and nothing comes back: no order number, no error, no way to tell from where you are sitting whether you now own the name. The only thing to do is run it again. Two mechanisms are supposed to make that retry safe, and both of them were mine to get right. My HTTP layer will not retry a POST on its own, because it cannot know the endpoint is safe to repeat. Registration sends an idempotency key, so that if the first request did land, the second is recognized as the same purchase rather than a new one.
Both correct, and for a while both useless: the code that attached the key ran after the code that built the request, and overwrote whatever the caller had set with a fresh value. Every retry carried a new key. Nothing downstream had any way to tell the attempts apart, because I had removed the one thing that would have let it.
Nothing about that was visible from the outside. Both halves looked right in review, the tests passed, and the only symptom would have been a duplicate order on someone’s invoice. That is the shape of the bugs worth being afraid of here: quiet, financial, and discovered long after you wrote them.
Caveats
Where it will bite you
It is beta, and the version number means it. The sandbox exists for a reason: point a
profile at api.dev.name.com, register nonsense there, and find out what a command
prints before you run it against a real account.
A couple of things will refuse you on purpose. Registering a name under a trademark
claim requires its own explicit acknowledgement, and --yes will not supply it, for
the same reason it cannot answer the register prompt. Bulk dns import validates the
entire file before writing a single record, because the writes are not transactional
and a half-applied zone is worse than a rejected one.
The web UI is better than this at the things a web UI is good at. It is very good at showing you one domain. It is not good at showing you sixty, or at doing the same small thing to all of them on a schedule, and nothing but a person can drive it at all. Those are the jobs I built this for, and they are the jobs where the difference between a careful client and a shell script is a line item on a bill.