reserve 0.1.1

Check domain name availability across grouped extensions, straight from the registry
reserve-0.1.1 is not a library.

reserve

Find a domain name you can actually register.

reserve checks names across domain extensions grouped the way people actually think about them — by industry, by region, by how widely they are used. Filter the list, sort it, page through it, and sweep it. Answers come from the registry itself, and a lookup that cannot be answered is reported as unknown rather than guessed.

Documentation: reserve.devops.bd

$ reserve extensions --group tech --page-size 6

EXTENSION  RANK  KIND     USED FOR
com           1  generic  business, tech, shop
net           4  generic  tech, business
xyz           7  generic  tech, creative, crypto
co           21  country  Colombia · business, tech · often used off-label
site         30  generic  tech, creative
app          35  generic  tech

1-6 of 35 extensions · page 1 of 6 · sorted by popularity (most used first)
next: --page 2  |  --all-pages

How it decides

Three sources are tried in order, and only the first two can prove a name is free.

  1. The registry's structured service. Authoritative. A "no such object" answer is a fact, not an inference. Covers about 1,200 extensions.
  2. The registry's text service on port 43. The only thing that answers for many country extensions, including Bangladesh's own. reserve bundles a table of 883 servers generated from IANA's own records, plus servers verified by live query that IANA does not publish.
  3. DNS. Fast, and only ever proves a name is in use. A name absent from DNS may be registered and simply never delegated, so DNS alone never produces an "available" verdict.

Pick one with --source registry, --source text, or --source dns. The default tries all three.

$ reserve example --tld com.bd,net.bd,org.bd,com,dev,io

+  example.co.bd   AVAILABLE  text       545ms
-  example.com     TAKEN      registry  1391ms
-  example.com.bd  TAKEN      text       420ms
-  example.dev     TAKEN      registry   553ms
-  example.io      TAKEN      registry  1269ms
+  example.net.bd  AVAILABLE  text      1538ms

2 available  4 taken  0 unknown   (6 checked)

Why it exists

Most availability checkers give you a flat list of extensions and a yes or no. Two things go wrong with that.

The first is scale. There are more than 1,400 delegated extensions. A flat list is unusable, and sweeping all of them wastes the registry's patience and yours. reserve groups them so you can ask for the twenty-five that matter to a software company, or the country zones for South Asia, without hand-writing a list.

The second is coverage. Bangladesh's .bd has no structured service and IANA publishes no server for it, so most tools report it as unanswerable. reserve carries the working server and answers every .bd zone, at both the second and third level.

The third is honesty. Registries throttle bulk clients, and the older text protocol carries no status codes at all — a refusal arrives as ordinary text down the same socket as a real answer. Tools that cannot tell the difference report the whole zone as free the moment they get throttled. reserve treats every unanswerable lookup as unknown, with the reason attached, and never as available.

Picking extensions

Extensions are grouped four ways. reserve groups lists them all.

  • By industrytech, shop, business, media, finance, health, education, food, travel, realestate, legal, crypto, creative, nonprofit
  • By regionsouth-asia, southeast-asia, east-asia, europe, north-america, latin-america, africa, middle-east, oceania
  • By popularitytop-10, top-25, top-50, top-100, ranked by how many names are actually registered in each zone
  • Hand-pickedpopular, classic, country-codes, domain-hacks, all, everything

Group membership is computed from extension metadata rather than stored as a list, so a group can never drift out of step with the data behind it. Groups combine — ask for two and you get the union of both.

reserve example --group tech
reserve example -g tech -g creative
reserve example -g south-asia --depth second

Naming what to check

reserve example                      # a bare name, crossed with the chosen extensions
reserve apple.com                    # a full domain, checked exactly as typed
reserve one two three --tld com,dev  # several names at once
reserve --names-from shortlist.txt   # read names from a file
reserve example --tlds-from zones.txt

A name carrying a dot is a domain you are asking about directly, so it is checked as given whatever extensions the run selected. A list file takes one entry per line, commas also separate, # starts a comment, blank lines are skipped, and duplicates are dropped.

The picker

Run reserve with a name and no extensions, at a terminal, and it opens a picker instead of guessing:

┌ Groups ──────────────────────┐┌ Extensions (35 chosen) - active ─────────┐
│ By industry                  ││ [x] com      1  generic                  │
│   tech            35         ││ [x] net      4  generic                  │
│   shop            15         ││ [x] xyz      7  generic                  │
│ By region                    ││ [ ] dev     59  generic                  │
│   south-asia      29         ││ [ ] app     35  generic                  │
└──────────────────────────────┘└──────────────────────────────────────────┘
 tab pane · space toggle · / search · a all · n none · enter go · q quit

Arrow keys or j/k move, tab switches pane, space toggles one extension or a whole group, / searches by extension, country, or industry, a selects everything shown, n clears, enter runs the sweep, q quits.

It never opens where there is nobody to answer: piped input, --no-input, or naming any extension all skip it, so a script behaves the same every time. --interactive forces it open.

Filtering

Filters narrow whatever you selected. They all combine.

  • --search <TEXT> matches the extension, its country, and its industries
  • --industry <KEY> and --region <KEY> narrow to a sector or a part of the world
  • --cctld keeps only two-letter country extensions
  • --depth second|third separates plain extensions from multi-label ones such as co.uk
  • --length 2, -3, 4-, or 2-4 filters by length, measured on the delegated label
  • --exclude <EXT> drops an extension from whatever else was chosen
  • --include-restricted adds zones the public cannot register under, hidden by default

Restricted zones are carried in the catalog but excluded from a sweep by default, so a free name in a zone nobody can buy is never offered to you as available.

Sorting and paging

reserve extensions --sort popularity          # most registered first
reserve extensions --sort length --order asc  # shortest first
reserve extensions --sort name --order desc   # z to a

Each field runs the direction that reads best for it unless you say otherwise. Popularity counts down; length and name count up. An extension with no rank always sorts to the bottom whichever direction you choose, so reversing a sort never floats unknown data to the top.

Results are paged to whatever your terminal fits, so a sweep across hundreds of extensions never scrolls away.

reserve extensions -g all --page 3
reserve extensions -g all --page-size 40
reserve extensions -g all --all-pages

Seeing more

reserve apple.com --details        # registrar, dates, status, nameservers, DNSSEC, abuse
reserve apple.com --responder      # which server answered
reserve apple.com --dns            # A, AAAA, NS, MX, TXT, SOA records
reserve example --where-to-buy     # registry page and prefilled registrar searches
reserve apple.com --full       # every section at once

The where-to-buy links are prefilled searches in a fixed order, not an offer and not a claim that a given registrar carries that extension. Their pages will say.

Saving results

reserve example -g tech --save            # available.txt, unavailable.txt, unknown.txt
reserve example -g tech --out results     # into a directory you name
reserve example -g tech --save --json     # the same three files as JSON arrays
reserve example -g tech --save --append   # merge into what is already there

Files are written to a temporary file and renamed into place, so an interrupted run never leaves a half-written file. An unknown result is always written to its own file, so a lookup that could not be answered is never filed among the available ones.

Pointing at your own servers

reserve example --registry-servers mine.json   # your own structured-service list
reserve example --text-servers mine.json     # your own text-service table
reserve example --text-servers mine.json --servers-replace   # replace rather than overlay
reserve example --no-referral                  # never ask IANA who serves an extension

By default a supplied list overlays the built-in one, so your entries win for the extensions they name and everything else still works. --servers-replace replaces it instead, which is how you reach an internal zone that has no public entry at all.

When nothing the tool already knows about answers, it asks IANA who serves that extension today, which repairs a built-in host that has gone stale. That extra lookup is cached per extension for the run, and --no-referral turns it off.

On prices

reserve deliberately shows no prices.

There is no single price for a domain extension. Comparing two of the most transparent registrars across the 405 extensions both of them price, the same extension differs by anywhere from 66 percent below to 39 percent above. Registry premium names sit outside every published list and can cost thousands. Figures exclude taxes, which depend on where you are. Wholesale prices move on scheduled dates.

A price column would imply a precision that does not exist. Check the price at the registrar you actually intend to buy from.

Reading a text answer

The older protocol has no status codes. "Not registered", "you are asking too fast", and "I do not serve that extension" all arrive as ordinary prose down the same socket, which is why tools built on it report whole zones as free the moment they get throttled.

reserve gathers every signal in an answer and then weighs them, rather than taking the first phrase that matches. That matters on real registries: one answers a taken name with Domain Status: Error followed by Message: Domain already registered, and a first-match rule calls a plainly registered name unknown. Matching is also negation-aware, because a registry that answers Available or Not Available will otherwise have every taken name in its zone reported as free.

A registry that says a specific name is blocked or reserved is reported as such, not as available and not as an error.

Pacing

A sweep across hundreds of extensions can hammer a small number of servers, because one operator often answers for hundreds of extensions from a single endpoint. reserve paces itself per registry host, never per extension — a per-extension limiter would multiply the real request rate by the number of extensions in the sweep and earn an immediate block.

  • a global cap on lookups in flight
  • a per-registry token bucket and concurrency cap, seeded from each operator's published limit where one exists and a cautious default where none does
  • a breaker that stops asking a registry that has started refusing, waits, then sends a single probe before resuming
  • backoff drawn uniformly from zero up to a ceiling that doubles with each refusal, so requests that fail together do not retry together
  • a registry's own stated retry delay honoured as given, capped so a mistaken hint cannot stall a run

Pass --cautious to hold every endpoint to the cautious limit.

Commands

reserve groups                  # every group, by family
reserve groups --family region  # one family
reserve extensions              # browse the catalog
reserve extensions --json       # machine-readable, for scripts
reserve doctor                  # version, catalog, terminal, paths
reserve config path             # where settings, cache, and data live
reserve config keys             # every setting the config file accepts
reserve completions zsh         # shell completions

Exit codes

Scripts branch on these. They are a contract and do not change meaning within a major version.

  • 0 — the command succeeded; for a sweep, at least one name is available
  • 1 — the sweep ran and nothing is available
  • 2 — the arguments were wrong
  • 4 — the network could not be reached
  • 5 — a file could not be written
  • 130 — the run was interrupted

Every failure also carries a stable identifier, printed as code: group.unknown, so a script can branch without parsing prose.

Output

Results go to stdout. Progress, warnings, and errors go to stderr, so a pipe receives only data. When stdout is not a terminal the decoration is dropped and the output stays parseable. A closed pipe ends the run quietly instead of panicking.

Colour follows the usual conventions in order: an explicit --color flag wins, then NO_COLOR, then FORCE_COLOR and CLICOLOR_FORCE, then a dumb terminal, then whether the stream is a terminal at all. Colours come from the sixteen named terminal colours, so retheming your terminal rethemes the tool. Meaning is never carried by colour alone — a symbol or a word always carries it too.

Building

cargo build --release
cargo test --workspace

Rust 1.88 or newer. Shell completions and man pages are generated at build time from the same command definition the parser uses, so they cannot drift from the real flags.

The catalog

The extension catalog is generated, not hand-edited, so every entry carries the same fields.

python3 tools/build_catalog.py

Ranks and registration counts are second-level zone counts. A zone count is not the same as a registry's own figure, because a registered-but-undelegated name never appears in the zone. Country extensions that register at the third level, such as .bd and .lk, are undercounted by any zone walk, so their rank is left blank rather than stated wrongly.

Contributing

Issues and pull requests are welcome at devops-infinity/reserve. Security reports go through the process in SECURITY.md rather than a public issue.

Licence

MIT. See LICENSE.