affix-domains

Attach popular brand prefixes/suffixes to a seed word and check availability against the authoritative registry. Starts at `.com`; if the seed word's own `.com` is taken, escalates the whole sweep to

SKILL.md

GitHub

affix-domains

Affix a seed word with common brand prefixes and suffixes, check each candidate live against the authoritative registry, against GitHub's org namespace, and against X's handle namespace, and prompt the user to register the free ones.

Steps

  1. Gate on the bare seed's .com. Before generating anything, check <seed>.com alone. It decides which lanes step 3 runs:

    • Free → the seed itself is winnable. Say so up front, then run the affix sweep on .com only — the original contract.
    • Taken → escalate. Every check from here on runs across the full TLD set: .com .net .org .ai .io .co .app .cc. Also sweep the bare seed across the other seven — mate.ai is worth more than matebuddy.com, and it costs eight lookups to find out.
  2. Generate candidates. For seed W, produce W + each suffix and each prefix + W from the catalog below. Lowercase. Dedupe. Always drop triple-letter runs (mateee) and a suffix that repeats the seed (matemate).

    The English-word filter is mode-dependent: in .com-only mode, drop any combination that spells an existing English word (e.g. getup, openbox) — its .com is almost certainly taken and burns a lookup. In escalated mode, keep them — that rationale is .com-specific, and a real word gone in .com says nothing about .ai or .cc. (mately is a dictionary adverb and the flagship -ly SaaS pattern; it is free in six TLDs.) If the user hints a style (playful, techy, marketplace…), weight the matching categories; default is every category.

    Write the candidates as bare names, one per line, in catalog rank order, to a fresh run dir; in escalated mode the bare seed is the first line:

    RUN=$(mktemp -d -t affix-<seed>) && printf '%s\n' "${cands[@]}" > "$RUN/names"
    

    Every lane checks names in file order, so when a quota trips late in a run its UNKNOWNs land on the lowest-ranked names.

  3. Run the sweep: every lane at once, as background jobs.

    ~/.claude/skills/affix-domains/scripts/sweep.sh com "$RUN"         # .com-only mode
    ~/.claude/skills/affix-domains/scripts/sweep.sh escalated "$RUN"   # full TLD set
    

    A lane is one rate-limit pool, checked by one bundled script over all of $RUN/names: com,net · cc · org · ai,io · app · co (com alone in .com-only mode) · GitHub · X. .com/.net share Verisign's host and .ai/.io share Identity Digital's, so each pair stays one lane: two jobs on one pool add no speed and trip its quota sooner. GitHub and X check every candidate, not only domain survivors, so they run beside the domain lanes instead of after them; one sweep fits inside both budgets. Each lane re-runs its UNKNOWN lookups once as soon as it ends, and skips a TLD that came back mostly UNKNOWN, with a sweep: line on stderr naming it. The sweep takes as long as its slowest lane, usually X at about one name a second.

    It prints one line per name, in rank order: <name>\t<FREE TLDs, best first>\t<UNKNOWN TLDs>\t<github>\t<x>, with - for none. The raw lane files stay in $RUN; scripts/merge.sh "$RUN" reprints the table.

    UNKNOWN is not FREE. It means the registry never gave a clean answer. Never show it as available; if a lookup is still UNKNOWN after the sweep, say so explicitly.

  4. Read the GitHub and X columns. They check the name, not the domain — a brand needs its handles as much as the domain: GitHub is where the code will live, X is where it will be announced. For both, only FREE is claimable. The GitHub verdicts:

    • TAKEN — users and orgs share one namespace, so a name some person holds is exactly as gone as one an org holds.
    • RESERVED — GitHub's own route namespace (settings, new, about, explore, login…). Never claimable, and it is the trap: these 404 on the API and only reveal themselves as a 30x redirect on the web.
    • INVALID — breaks GitHub's account-name rules: anything outside alphanumerics and single interior hyphens, or over 39 characters. Also 404s, so it is screened before the lookup.

    check_x.sh runs in two stages. First twitter user <name> — twitter-cli on your own logged-in Chrome session, two lanes, about 2 s a name: a profile means TAKEN, and that is all stage one decides. Every other name — no profile, or any twitter-cli error — goes to X's sign-up availability check, which is what splits them into FREE, RESERVED and INVALID — a profile miss alone is never FREE. After the sweep the script re-queries every FREE once, serially, and prints the re-check's verdict; you do not repeat that. The script installs twitter-cli with uv tool install twitter-cli when it is missing; when it is installed but not logged in on this host, it says so on stderr and runs the sign-up stage over every name instead, with the same verdicts. The X verdicts:

    • TAKEN — a profile exists; one namespace, case-insensitive: GetMate and getmate are the same handle. A suspended or deactivated account counts — X holds the handle, a deactivated one for at least 30 days.
    • RESERVED — X's sign-up refuses it. That covers route words (home, settings, explore, i, search, login…), anything containing twitter or admin, and a held set of ordinary-looking handles (matearoo, evermate) that show no profile page yet can never be claimed. Never claimable, and it is the trap: x.com/<name> 404s on those, exactly as GitHub's API does on its reserved names.
    • INVALID — outside [A-Za-z0-9_], shorter than 5, or longer than 15; screened locally, so it costs no request. The two namespaces disagree here: GitHub allows hyphens and 39 characters, X allows underscores and 15 — a long candidate can be valid on GitHub and INVALID on X, and that is a real answer, not an error.
  5. Surface the survivors. In .com-only mode, list one line per free .com, in catalog rank order (note each name's category).

    In escalated mode the raw cross-product is far too long to dump. Instead, keep the sweep's order: names by their affix's catalog rank, each name's free TLDs in this preference order:

    .com > .ai > .io > .co > .net > .org > .app > .cc

    Show the best one or two TLDs per name, and offer the complete matrix only if the user asks. Note when a name is free across many TLDs — that usually means it is genuinely unclaimed rather than merely available in the leftovers.

    Carry the GitHub and X verdicts on the same line as the name, in both modes — two columns, not two more lists; the user is picking a brand, and the domain, the org and the handle are one decision. A name where the domain, the org and the handle are all free is the strongest result the sweep can return: lead with those, and say so. Where a name's domain is free but the org or the handle is taken, keep it on the list and mark which — it is still registrable, just with a handle compromise ahead.

  6. Prompt the user to register. Ask which they want to take. Point them to Cloudflare Registrar (or their preferred one) — note that Cloudflare Registrar does not sell every TLD in this set, so a second registrar may be needed. Do not enter payment on their behalf — registration is the user's action.

    For the matching GitHub org, point them at https://github.com/organizations/new — free, no payment, seconds to claim. Worth saying plainly: an org name costs nothing and is first-come, so it is the cheapest part of the brand to lose by waiting. Creating it is still the user's action, not yours.

    The X handle is claimed by signing up at https://x.com/i/flow/signup with that username, or by renaming an existing account at https://x.com/settings/screen_name. Free and first-come like the org, and the same rule: the user claims it, not you.

TLD endpoints

Verified 2026-08-27, each against a known-taken and a known-free control. The script holds these; the table is here so a human can audit it.

TLD Method Endpoint Notes
.com RDAP rdap.verisign.com/com/v1/domain/ Verisign, authoritative
.net RDAP rdap.verisign.com/net/v1/domain/ Verisign
.cc RDAP tld-rdap.verisign.com/cc/v1/domain/ Verisign, but a different host than .com/.net
.org RDAP rdap.publicinterestregistry.org/rdap/domain/ PIR
.ai RDAP rdap.identitydigital.services/rdap/domain/ Identity Digital
.io RDAP rdap.identitydigital.services/rdap/domain/ same host as .ai; not in the IANA bootstrap
.app RDAP pubapi.registry.google/rdap/domain/ Google Registry; rate-limited, see below
.co WHOIS whois.registry.co No RDAP service exists. Free ⇔ DOMAIN NOT FOUND

.app rate limiting is a rolling quota, not a concurrency cap. Dropping to -P 2 does not help — once the budget is spent, every request 429s regardless of parallelism. The only fix is serial requests plus backoff-and-retry, which is what the script does. Treat 429 as retry, never as an answer.

.ai and .io share one host, and so share one quota. rdap.identitydigital.services serves both at -P 6, so an escalated sweep hits it with twice the requests of any other host and can exhaust it late in the run — observed 2026-09-16 on a 67-name sweep, where the last 13 .io lookups all came back UNKNOWN while .com and .cc were clean. Once it is tripped the block is long — measured at over 150s of cumulative backoff on a single name without clearing, so neither the script's 4-attempt loop nor a hand-rolled serial retry with 10s-and-up sleeps will outlast it inside a session. Do not grind: a full serial retry of 13 names costs ~30 minutes and can still return all UNKNOWN. Report those lookups as unresolved, name the TLD and the cause, and say they can be re-checked in a later session. Spending the quota more slowly does not buy more of it. A block of UNKNOWNs confined to one TLD is a quota symptom, not a registry answer — never let it reach the user as availability, in either direction.

GitHub org namespace

Verified 2026-09-16 against four controls: github (org) 200, soulmachine (user) 200, agentsyncaroo (free) 404, settings and new (reserved) 302.

Target Method Endpoint Notes
GitHub org/user name HTML status https://github.com/<name> 404 free · 200 taken · 301/302 reserved. No token, no API budget; P8 is comfortable

Do not use api.github.com/users/<name> for this. It answers 404 for GitHub's reserved route names — settings, new, about, explore, login — which would be reported as available when they can never be registered. Only the web endpoint separates reserved from free, by redirecting instead of 404ing. The API is also capped at 60 requests/hour unauthenticated, which a single 67-name sweep blows straight through.

X handle namespace

Verified 2026-09-18. Stage 1 controls: x taken (the preflight's own call, past the local screen), soulmachine hollow (held), agentsyncaroo and matearoo not found. Stage 2 controls: agentsyncaroo available, explore is_banned_word, twitteradmin contains_banned_word; get-mate, abc and abcdefghijklmnop are INVALID from the local screen and never reach either stage (home is four characters, so it is INVALID too, however famous the account).

Stage Question Method Endpoint Notes
1 profile exists? twitter-cli user <name> --json GraphQL UserByScreenName on the user's Chrome session ok:true taken — an empty id is X's UserUnavailable, a held handle; code:not_found and any other code fall through to stage 2. About 2 s a name; the session limit is community-reported at ~95 per 15 min, and twitter-cli retries a 429 itself (5/10/20 s) before surfacing it, so a second sweep inside the window runs slower, not emptier
2 registrable? JSON reason field api.x.com/i/users/username_available.json?username=<name> X's own sign-up check, unauthenticated, no API credits, case-insensitive: available free · taken · is_banned_word / contains_banned_word reserved · invalid_username / improper_format invalid

Stage 2 has a budget of about 250 requests per IP, then a 429 that lasts minutes; a burst on the first 200 re-trips it, and fifteen quiet minutes clears it. A sweep sends it only the no-profile names — 18 of 66 in the mate sweep — so it fits many times over; if the column still goes UNKNOWN part-way through, that is the quota, not a registry answer: report those names unresolved and re-run only them after the quiet period.

For a few ordinary-looking names the sign-up answer is not stable. Measured 2026-09-18 on a calm endpoint, serially, nothing else in flight: mateora answered available, then is_banned_word sixty seconds later; quickmate did the same across runs; matehub answered available early in the day and is_banned_word from twenty minutes on. The twelve other banned mate handles held across every query. No name that answered taken ever answered available, but mateor (taken) did answer is_banned_word once, in a run that was also drawing 429s — a flicker can land on a taken name too, and both answers are not-claimable. Which of the two answers is true for a flickering free name cannot be settled without registering it, so the rule is: a FREE that does not repeat is not FREE. The script re-queries every FREE once after the sweep, serially, and prints that second verdict verbatim, whatever it is; the flicker itself is worth a sentence to the user. RESERVED from a clean run is otherwise reliable. Querying a name does not put it on hold — 250 probe names checked once still read available 35 minutes later — but FREE is still a snapshot: re-check the shortlist right before the user claims it.

Endpoints that look right and are wrong

Both of these return HTTP 404 for domains that are definitely registered — a silent false-available that would tell the user to go buy a taken domain. Do not substitute them:

  • rdap.godaddy.com/v1/domain/ — 404s on t.co. It is the registrar's RDAP, not the registry's.
  • rdap.org/domain/ — a bootstrap proxy; 404s on both .co and .io because neither is in the IANA bootstrap file.

And for the X handle, both of these would report a reserved handle as free:

  • https://x.com/<name> HTTP status — 404 for free names, but also 404 for held handles like matearoo and evermate, which sign-up refuses as is_banned_word. It encodes none of the sign-up rules.
  • X API v2 GET /2/users/by/username/<name> (via xurl, or the xapi MCP's user lookup) — answers "does an account exist", not "can you register it", so reserved words and held handles come back not-found. It also spends API credits, which neither stage does; the DomainHunter app answered 402 credits depleted on 2026-09-18.
  • twitter-cli's not_found on its own — it is stage 1, not a verdict: matearoo is not_found there and refused by sign-up. Only the sign-up check promotes a no-profile name to FREE.

Catalog ranking

Both catalogs are ranked by evidence: how often the hottest AI startups actually use each affix in their brand names — a 433-company corpus (Forbes AI 50 2026+2025, CB Insights AI 100 2026, YC, a16z Top-100 consumer apps, LinkedIn Top Startups US, 2025–26 mega-rounds, AI dev-tools peer group; snapshot 2026-08-28) — blended with fusability and meaning (Score = 2·E + F + M). Generate candidates from every row, but check and surface them in rank order. The full evidence tables (scores, old-vs-new ranks, corpus examples) are in references/ranking-2026-08.md. Known catalog gap, deliberately not auto-added: the era's dominant suffix is a trailing "AI" word (~60 hot companies), plus -lab, -0, -gpt, applied- — see the reference before extending the catalog.

Prefix catalog — ranked

# Affix Category Hot uses 2025–26 Feel · exemplars
1 deep- Scale & depth 4 serious tech (DeepMind, DeepSeek)
2 open- Newness & openness 4 transparent/community (OpenAI, OpenTable)
3 super- Scale & depth 2 boosted (Superhuman)
4 live- Newness & openness 2 real-time (LiveChat)
5 agent- AI & agents 2 autonomous doer (Agentforce)
6 ai- AI & agents 3 AI-native signal (AI21)
7 up- Scale & depth 1 rising (Upwork)
8 hey- Call-to-action 1 friendly hail (Hey.com)
9 chat- AI & agents 1 conversational (ChatGPT)
10 the- Possessive 1 definitive (TheVerge)
11 go- Call-to-action 0 momentum (GoDaddy, GoPro)
12 fast- Speed & ease 0 velocity (Fastly)
13 get- Call-to-action 0 grab it (GetResponse)
14 next- Newness & openness 0 successor (NextDoor)
15 quick- Speed & ease 0 instant (QuickBooks)
16 smart- Speed & ease 0 intelligent (SmartThings)
17 my- Possessive 0 personal (MySpace, MyFitnessPal)
18 easy- Speed & ease 0 frictionless (EasyJet)
19 ever- Scale & depth 0 permanence (Evernote)
20 real- Newness & openness 0 authentic (RealPage)
21 neo- Newness & openness 0 new wave (Neobank)
22 hyper- Scale & depth 0 past the limit (Hyperloop, Hyperscience)
23 use- Call-to-action 0 utility (Usebutton)
24 try- Call-to-action 0 low-commitment invite
25 ultra- Scale & depth 0 extreme
26 meta- Newness & openness 0 beyond (Meta)
27 meet- Call-to-action 0 introduction (MeetUp-style)
28 agentic- AI & agents 0 agent-native workflows (agentic AI wave)
29 join- Call-to-action 0 community invite
30 every- Scale & depth 0 universality (Everlane-like)

Suffix catalog — ranked

# Affix Category Hot uses 2025–26 Feel · exemplars
1 -labs Tool & hub 12 R&D shop (Bell Labs)
2 -o Vowel endings 11 punchy (Venmo)
3 -a Vowel endings 10 smooth (Tesla, Zara)
4 -er Doer 4 actor/agent (Uber, Tinder)
5 -ia Vowel endings 3 name-like (Nvidia, Expedia)
6 -base Tool & hub 2 foundation/platform (Coinbase, Firebase, Supabase)
7 -ly Short & modern 3 SaaS all-rounder (Bitly, Calendly, Grammarly)
8 -r Short & modern 3 drop-vowel web-2.0 (Tumblr, Flickr)
9 -us Vowel endings 4 Latin gravitas (Prius)
10 -ify Verbifier 1 turns the word into a service (Spotify, Shopify)
11 -kit Tool & hub 1 toolkit (ConvertKit)
12 -bot Companion 1 automated agent
13 -ora Vowel endings 1 elegant Latin (Pandora)
14 -cast Vertical positioning 1 media/broadcast (Podcast)
15 -verse Stylized & meme 1 a whole universe (metaverse)
16 -app Vertical positioning 1 application (Cash App)
17 -hub Tool & hub 0 gathering point (GitHub)
18 -stack Tool & hub 0 tech stack (Substack)
19 -or Doer 1 mechanical (Vector)
20 -ee Vowel endings 1 soft (Renee-like)
21 -box Tool & hub 0 packaged tool (Dropbox)
22 -mate Companion 0 sidekick (Mailmate)
23 -works Tool & hub 0 workshop (SolidWorks)
24 -pal Companion 0 trusted friend (PayPal)
25 -pad Tool & hub 0 workspace (Launchpad)
26 -ize Verbifier 0 systematize (Rentalize)
27 -ist Doer 0 specialist (Stylist)
28 -space Tool & hub 0 room to work (Squarespace)
29 -buddy Companion 0 friendly helper (GasBuddy)
30 -ix Vowel endings 0 techy (Netflix)
31 -matic Stylized & meme 0 machine-magic (Instamatic)
32 -bay Vertical positioning 0 marketplace (eBay)
33 -ex Vowel endings 0 sharp, techy (FedEx)
34 -y Short & modern 0 cute, casual (Etsy)
35 -ate Verbifier 0 automate/activate (Automate)
36 -x Short & modern 0 edgy, techy (Codex)
37 -zilla Stylized & meme 0 monster-big (Mozilla)
38 -oo Vowel endings 0 round, cute (Yahoo)
39 -aroo Stylized & meme 0 bouncy-cute (Kangaroo)

Rules

  • Live lookups only — never claim availability from cached knowledge or prior turns of this conversation. Domains, org names and handles get registered between checks.
  • Only an explicit negative means available. RDAP 404, WHOIS DOMAIN NOT FOUND, github.com/<name> returning 404, or X's sign-up check answering "reason":"available". Anything else — 429, 5xx, a timeout, an empty body, a 30x — is UNKNOWN or RESERVED, reported as such and never as free.
  • Use the bundled scripts rather than hand-rolled curl or a bare twitter user. sweep.sh runs the other three: check_domains.sh for TLDs, check_github.sh for the org name, check_x.sh for the X handle. The per-TLD hosts, the .co WHOIS special case, the .app retry loop, GitHub's reserved-name redirect, and X's two-stage split are all easy to get wrong in a way that fails silently toward false-available.
  • The escalated TLD set is fixed: .com .net .org .ai .io .co .app .cc. If the user wants a TLD outside it, check it explicitly and say the endpoint was not pre-verified.
  • A free domain with a taken org or handle is still a result — report it, marked, rather than dropping it. The three namespaces are independent and the user may not care equally about all of them; suppressing part of the picture makes that call for them.
  • Never report a GitHub name as available on the strength of an API 404, nor an X handle on the strength of an x.com/<name> 404, a v2 API not-found, or a twitter-cli not_found alone — see the reserved-name traps above. GitHub's web endpoint and X's sign-up check, or nothing.
  • No payment on the user's behalf. Prompt them to register; they check out. Same for creating the GitHub org and claiming the X handle, which cost nothing but are still theirs to do.