quien — Better WHOIS Lookup Tool Skill by ara.so — Daily 2026 Skills collection. quien is a Go-based CLI/TUI tool that replaces whois with tabbed interactive views and JSON-scriptable subcommands for domain WHOIS/RDAP, DNS records, mail configuration (SPF, DMARC, DKIM, BIMI), SSL/TLS, HTTP headers, tech stack detection, and IP/ASN/BGP lookups. Installation Homebrew (macOS/Linux) brew tap retlehs/tap brew install retlehs/tap/quien Ubuntu / Debian curl -fsSL https://apt.quien.dev/install.sh | sudo sh Go go install github.com/retlehs/quien@latest Verify installation quien --version Optional — replace system whois:
Add to ~/.bashrc or ~/.zshrc
alias whois = quien Core CLI Commands Interactive TUI (default)
Launch interactive prompt
quien
Open TUI directly for a domain
quien example.com
Open TUI for an IP address
quien 8.8 .8.8 JSON output (scriptable)
Full JSON output for all tabs
quien --json example.com
Individual subcommands (always output JSON)
quien dns example.com quien mail example.com quien tls example.com quien http example.com quien stack example.com quien all example.com
all data in one JSON object
TUI Tab Overview Tab Data shown WHOIS RDAP-first registration data, registrar, dates, nameservers DNS A, AAAA, MX, TXT, NS, CNAME, SOA records Mail MX, SPF, DMARC, DKIM, BIMI + VMC chain validation TLS Certificate chain, validity, SANs, cipher info HTTP Response headers, redirects, status codes Stack WordPress plugins, JS/CSS frameworks, external services IP Reverse DNS, network info, abuse contacts, ASN via RDAP/BGP JSON Subcommand Examples DNS records quien dns github.com
Output:
{
"domain": "github.com",
"a": ["140.82.121.4"],
"aaaa": [],
"mx": [{"host": "aspmx.l.google.com", "priority": 1}],
"ns": ["dns1.p08.nsone.net", "dns2.p08.nsone.net"],
"txt": ["v=spf1 ip4:... ~all"],
...
}
Mail configuration audit quien mail example.com
Returns SPF record, DMARC policy, DKIM selectors found,
BIMI record, VMC certificate chain validation
TLS/SSL inspection quien tls example.com
Returns certificate subject, issuer, validity dates,
SANs, chain depth, protocol version, cipher suite
HTTP headers quien http example.com
Returns status code, redirect chain, all response headers
(Content-Security-Policy, HSTS, X-Frame-Options, etc.)
Tech stack detection quien stack example.com
Parses HTML for:
- WordPress version + active plugins
- JavaScript frameworks (React, Vue, Angular, Next.js, etc.)
- CSS frameworks (Tailwind, Bootstrap, etc.)
- External services (analytics, CDNs, payment providers)
IP address lookup quien 8.8 .8.8 quien --json 8.8 .8.8
Returns:
- Reverse DNS (PTR record)
- RDAP network block info
- Abuse contact
- Origin ASN + prefix (RDAP with BGP fallback)
- PeeringDB enrichment: org, peering policy, IX/facility counts,
traffic profile, peering locations
All data at once quien all example.com | jq '.dns.a' quien all example.com | jq '.mail.spf' quien all example.com | jq '.tls.valid_until' Scripting Patterns Pipe JSON into jq
Get all A records
quien dns example.com | jq '.a[]'
Check if DMARC policy is reject
quien mail example.com | jq '.dmarc.policy == "reject"'
Get certificate expiry
quien tls example.com | jq '.certificates[0].not_after'
List detected JS frameworks
quien stack example.com | jq '.javascript_frameworks[]'
Get ASN number for an IP
quien --json 1.1 .1.1 | jq '.asn.number' Shell script: bulk domain audit
!/bin/bash
domains
( "example.com" "github.com" "golang.org" ) for domain in " ${domains [ @ ] } " ; do echo "=== $domain ===" spf = $( quien mail " $domain " | jq -r '.spf.record // "MISSING"' ) dmarc = $( quien mail " $domain " | jq -r '.dmarc.policy // "MISSING"' ) tls_expiry = $( quien tls " $domain " | jq -r '.certificates[0].not_after // "N/A"' ) echo "SPF: $spf " echo "DMARC: $dmarc " echo "TLS expires: $tls_expiry " echo done Shell script: check domain expiry
!/bin/bash
DOMAIN
- "
- ${1
- :?
- Usage
- :
- $0
} - "
- expiry
- =
- $(
- quien
- --json
- "
- $DOMAIN
- "
- |
- jq
- -r
- '.whois.expires // .rdap.expires // empty'
- )
- if
- [
- -z
- "
- $expiry
- "
- ]
- ;
- then
- echo
- "Could not determine expiry for
- $DOMAIN
- "
- exit
- 1
- fi
- echo
- "
- $DOMAIN
- expires:
- $expiry
- "
- Go integration — run quien as subprocess
- package
- main
- import
- (
- "encoding/json"
- "fmt"
- "os/exec"
- )
- type
- DNSResult
- struct
- {
- Domain
- string
json:"domain"- A
- [
- ]
- string
json:"a"- MX
- [
- ]
- struct
- {
- Host
- string
json:"host"- Priority
- int
json:"priority"- }
json:"mx"- TXT
- [
- ]
- string
json:"txt"- }
- func
- lookupDNS
- (
- domain
- string
- )
- (
- *
- DNSResult
- ,
- error
- )
- {
- out
- ,
- err
- :=
- exec
- .
- Command
- (
- "quien"
- ,
- "dns"
- ,
- domain
- )
- .
- Output
- (
- )
- if
- err
- !=
- nil
- {
- return
- nil
- ,
- fmt
- .
- Errorf
- (
- "quien dns failed: %w"
- ,
- err
- )
- }
- var
- result DNSResult
- if
- err
- :=
- json
- .
- Unmarshal
- (
- out
- ,
- &
- result
- )
- ;
- err
- !=
- nil
- {
- return
- nil
- ,
- fmt
- .
- Errorf
- (
- "parse error: %w"
- ,
- err
- )
- }
- return
- &
- result
- ,
- nil
- }
- func
- main
- (
- )
- {
- dns
- ,
- err
- :=
- lookupDNS
- (
- "example.com"
- )
- if
- err
- !=
- nil
- {
- panic
- (
- err
- )
- }
- fmt
- .
- Printf
- (
- "A records for %s: %v\n"
- ,
- dns
- .
- Domain
- ,
- dns
- .
- A
- )
- for
- _
- ,
- mx
- :=
- range
- dns
- .
- MX
- {
- fmt
- .
- Printf
- (
- "MX %d: %s\n"
- ,
- mx
- .
- Priority
- ,
- mx
- .
- Host
- )
- }
- }
- Go integration — full audit struct
- package
- main
- import
- (
- "encoding/json"
- "os/exec"
- )
- type
- FullAudit
- struct
- {
- WHOIS
- struct
- {
- Registrar
- string
json:"registrar"- Created
- string
json:"created"- Expires
- string
json:"expires"- Updated
- string
json:"updated"- }
json:"whois"- DNS
- struct
- {
- A
- [
- ]
- string
json:"a"- NS
- [
- ]
- string
json:"ns"- TXT
- [
- ]
- string
json:"txt"- }
json:"dns"- struct
- {
- SPF
- struct
- {
- Record
- string
json:"record"- Valid
- bool
json:"valid"- }
json:"spf"- DMARC
- struct
- {
- Record
- string
json:"record"- Policy
- string
json:"policy"- }
json:"dmarc"- }
json:"mail"- TLS
- struct
- {
- Certificates
- [
- ]
- struct
- {
- Subject
- string
json:"subject"- NotAfter
- string
json:"not_after"- }
json:"certificates"- }
json:"tls"- Stack
- struct
- {
- JavascriptFrameworks
- [
- ]
- string
json:"javascript_frameworks"- CSSFrameworks
- [
- ]
- string
json:"css_frameworks"- ExternalServices
- [
- ]
- string
json:"external_services"- }
json:"stack"- }
- func
- auditDomain
- (
- domain
- string
- )
- (
- *
- FullAudit
- ,
- error
- )
- {
- out
- ,
- err
- :=
- exec
- .
- Command
- (
- "quien"
- ,
- "all"
- ,
- domain
- )
- .
- Output
- (
- )
- if
- err
- !=
- nil
- {
- return
- nil
- ,
- err
- }
- var
- audit FullAudit
- return
- &
- audit
- ,
- json
- .
- Unmarshal
- (
- out
- ,
- &
- audit
- )
- }
- Agent Skill Integration
- Install quien as an agent skill so AI coding agents automatically use it for domain/IP lookups:
- npx skills
- add
- retlehs/quien
- Key Behaviors to Know
- RDAP-first
-
- Uses RDAP protocol before falling back to raw WHOIS. Broader TLD coverage via IANA referral.
- Automatic retry
-
- All network lookups use exponential backoff — transient failures are retried automatically.
- BGP fallback
-
- If RDAP does not return ASN data for an IP, quien queries BGP routing tables for origin ASN/prefix.
- PeeringDB enrichment
-
- ASN lookups are enriched with PeeringDB data (peering policy, IX presence, traffic profile).
- VMC validation
-
- BIMI lookups validate the full VMC certificate chain, not just the record presence.
- Tech stack from HTML
- Stack detection fetches and parses the actual HTML of the target, not just HTTP headers. Troubleshooting quien: command not found
If installed via go install, ensure GOPATH/bin is in PATH
export PATH = " $PATH : $( go env GOPATH ) /bin" TUI doesn't render correctly
Ensure your terminal supports true color and UTF-8
echo $TERM
should be xterm-256color or similar
echo $LANG
should include UTF-8
Rate limiting / lookup failures RDAP and WHOIS servers may rate-limit. quien retries with backoff automatically. For bulk scripting, add sleep 1 between calls to avoid hitting rate limits. No DKIM results DKIM requires knowing the selector. quien probes common selectors (google, default, mail, etc.) but custom selectors won't be discovered automatically. IP lookup shows no ASN Some IP blocks are not in RDAP. quien falls back to BGP; if both fail, the block may be unrouted or private. JSON output is empty / malformed
Confirm the subcommand syntax — subcommands always output JSON
quien dns example.com
correct
quien --json dns example.com