quien-whois-lookup
Use quien for interactive TUI and CLI/JSON domain, IP, DNS, mail, SSL/TLS, and tech stack lookups
What this skill does
# quien — Better WHOIS Lookup Tool
> Skill by [ara.so](https://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)**
```sh
brew tap retlehs/tap
brew install retlehs/tap/quien
```
**Ubuntu / Debian**
```sh
curl -fsSL https://apt.quien.dev/install.sh | sudo sh
```
**Go**
```sh
go install github.com/retlehs/quien@latest
```
**Verify installation**
```sh
quien --version
```
**Optional — replace system whois:**
```sh
# Add to ~/.bashrc or ~/.zshrc
alias whois=quien
```
---
## Core CLI Commands
### Interactive TUI (default)
```sh
# 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)
```sh
# 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
```sh
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
```sh
quien mail example.com
# Returns SPF record, DMARC policy, DKIM selectors found,
# BIMI record, VMC certificate chain validation
```
### TLS/SSL inspection
```sh
quien tls example.com
# Returns certificate subject, issuer, validity dates,
# SANs, chain depth, protocol version, cipher suite
```
### HTTP headers
```sh
quien http example.com
# Returns status code, redirect chain, all response headers
# (Content-Security-Policy, HSTS, X-Frame-Options, etc.)
```
### Tech stack detection
```sh
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
```sh
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
```sh
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
```sh
# 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
```sh
#!/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
```sh
#!/bin/bash
DOMAIN="${1:?Usage: $0 <domain>}"
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
```go
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
```go
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"`
Mail 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:
```sh
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 fRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.