// SPECTR site bundle (auto-generated; sources in src/) const { useState, useEffect } = React; /* data */ // Packet stream rows — IT-heavy mix with OT/IoT/Wi-Fi cameos and anomalies sprinkled in. const PACKETS = [ { n: 1042, t: "14:32:01.284", proto: "HTTPS", domain: "it", src: "10.0.4.22", dst: "104.18.32.7", len: 517, desc: "TLSv1.3 · ja3 t13d1516h2_acb858a92679_3fdcc2ef9d8a" }, { n: 1043, t: "14:32:01.291", proto: "DNS", domain: "it", src: "10.0.4.22", dst: "1.1.1.1", len: 74, desc: "Standard query A sentry.io" }, { n: 1044, t: "14:32:01.298", proto: "TLS", domain: "it", src: "10.0.4.22", dst: "142.250.80.46", len: 1420, desc: "ClientHello · h2 alpn · sni=clients.google.com" }, { n: 1045, t: "14:32:01.305", proto: "HTTP", domain: "it", src: "10.0.4.91", dst: "203.0.113.44", len: 612, desc: "POST /upload?id=u8821 · Content-Type: application/octet-stream", anomaly: "crit", rule: "IT-EX-12", ai: { title: "Plaintext exfiltration to unrecognized host", body: "Host 10.0.4.91 POSTed 612B of application/octet-stream over cleartext HTTP to 203.0.113.44 — an IP never seen in the 14-day egress baseline. Destination ASN is a low-reputation hosting block. No User-Agent. No Referer.", rec: "Block 203.0.113.44 at the egress firewall. Quarantine 10.0.4.91 and pull its outbound HTTP history for the past 72 hours." } }, { n: 1046, t: "14:32:01.312", proto: "LDAP", domain: "it", src: "10.0.4.22", dst: "10.0.2.5", len: 286, desc: "bindRequest · simple · cn=svc-mon,ou=svc,dc=corp" }, { n: 1047, t: "14:32:01.319", proto: "MQTT", domain: "iot", src: "10.0.8.41", dst: "10.0.2.10", len: 128, desc: "Publish · sensors/bay-4/temp · QoS 1" }, { n: 1048, t: "14:32:01.326", proto: "KRB5", domain: "it", src: "10.0.4.137", dst: "10.0.2.5", len: 1188, desc: "TGS-REQ · 23 SPNs in 18s · etype=23 (RC4-HMAC)", anomaly: "crit", rule: "IT-ID-KRB", ai: { title: "Kerberoasting — high-rate TGS for service SPNs", body: "Host 10.0.4.137 requested 23 service tickets in 18 seconds, all targeting MSSQL/backup SPNs and all encrypted with RC4-HMAC. Modern domains negotiate AES; RC4 requests are the textbook offline-crackable Kerberoasting signature.", rec: "Pull the source host. Force a password rotation on every SPN in the request burst. Disable RC4-HMAC in the realm policy if not already." } }, { n: 1049, t: "14:32:01.333", proto: "HTTP", domain: "it", src: "10.0.4.22", dst: "10.0.2.40", len: 340, desc: "GET /api/v2/health · 200 OK" }, { n: 1050, t: "14:32:01.341", proto: "MODBUS", domain: "ot", src: "192.168.1.50", dst: "10.0.10.14", len: 78, desc: "FC16 Write Multiple · regs 40032..40033", anomaly: "crit", rule: "OT-W-03", ai: { title: "Unauthorized Modbus FC16 write to PLC", body: "Function code 16 (write multiple registers) issued from 192.168.1.50 to PLC 10.0.10.14. Source host is not in the authorized HMI subnet (10.0.9.0/24) and has never written to this PLC in the 14-day baseline. Target registers 40032–40033 control the bay-4 setpoint.", rec: "Isolate 192.168.1.50 and inspect preceding auth flows. No legitimate operational reason for a write from this VLAN." } }, { n: 1051, t: "14:32:01.348", proto: "SMB", domain: "it", src: "10.0.4.188", dst: "10.0.4.22", len: 180, desc: "Negotiate Protocol Request · dialects include SMB1", anomaly: "warn", rule: "IT-LM-11", ai: { title: "SMBv1 negotiation attempt — EternalBlue surface", body: "Host 10.0.4.188 initiated an SMB negotiate with SMB1 in the dialect list. SMBv1 is the attack vector for EternalBlue/WannaCry and has no legitimate use in a 2026 environment.", rec: "Disable SMBv1 on 10.0.4.188 via Group Policy. Review the host's patch level and EDR status." } }, { n: 1052, t: "14:32:01.355", proto: "DNS", domain: "it", src: "10.0.4.91", dst: "8.8.8.8", len: 144, desc: "Query TXT · aHR0cHM6Ly9jMi5leGFtcGxl.atk.example", anomaly: "crit", rule: "IT-EX-07", ai: { title: "DNS tunneling pattern", body: "Base64-shaped label (aHR0cHM6Ly9jMi5leGFtcGxl) in TXT query to atk.example. Query entropy 5.42 bits/char, length 144B — consistent with command-and-control over DNS.", rec: "Block atk.example at resolver. Pull full DNS history for 10.0.4.91 and quarantine." } }, { n: 1053, t: "14:32:01.362", proto: "RDP", domain: "it", src: "10.0.4.22", dst: "10.0.2.88", len: 412, desc: "Connection Request · cookie=mstshash=jwong" }, { n: 1054, t: "14:32:01.370", proto: "OPC-UA", domain: "ot", src: "10.0.9.51", dst: "10.0.10.21", len: 210, desc: "Read Request · 3 attributes" }, { n: 1055, t: "14:32:01.377", proto: "DOT11", domain: "wifi", src: "aa:bb:cc:11", dst: "ff:ff:ff:ff", len: 62, desc: "Beacon · ssid=corp-iot · ch 6 · -42 dBm" }, { n: 1056, t: "14:32:01.384", proto: "DNP3", domain: "ot", src: "10.0.10.14", dst: "10.0.9.7", len: 92, desc: "Unsolicited response · class 1 · obj 30 var 5" }]; const DOMAINS = [ { key: "it", label: "IT", name: "Enterprise traffic", desc: "29 protocols deep-parsed. JA3/JA3S passive + JARM active TLS fingerprinting, identity extraction from NTLMSSP, LDAP bind DN, and Kerberos SPN. Optional SSLKEYLOGFILE TLS decryption.", count: "29 protocols", protos: ["HTTP/2", "TLS 1.3", "DNS", "SMB", "Kerberos", "LDAP", "RDP", "SSH", "FTP", "NTP", "Syslog", "SIP/RTP", "gRPC", "WebSocket", "RADIUS", "LLMNR/NBNS"] }, { key: "iot", label: "IoT", name: "Device protocols", desc: "Lightweight protocols your asset inventory misses. MQTT topic-level awareness, CoAP observation, AMQP, and automatic device behavioral baselining.", count: "3 parsed", protos: ["MQTT", "CoAP", "AMQP"] }, { key: "ot", label: "OT / ICS", name: "Industrial control", desc: "Function-code level parsing for 9 OT protocols. Write detection, setpoint tracking, Purdue-zone classification, ICS-CERT advisory correlation, and process-historian comparison.", count: "9 protocols", protos: ["Modbus TCP/RTU", "DNP3", "OPC-UA", "EtherNet/IP", "BACnet", "S7comm", "IEC 60870-5-104", "PROFINET"] }, { key: "wifi", label: "Wireless", name: "802.11 visibility", desc: "Passive Radiotap + Dot11 parsing. Beacon, probe, auth/assoc/deauth, control + data frames. Linux monitor-mode automated; macOS/Windows guided. Optional SSLKEYLOGFILE TLS decryption on captured frames.", count: "4 wireless rules", protos: ["Beacon/Probe", "Auth/Assoc", "Deauth", "Control", "Data", "Radiotap"] }]; const ANOMALIES = [ { sev: "crit", rule: "OT-W-03", title: "Unauthorized Modbus write", body: 'pkt #1046 · src 192.168.1.50 → dst 10.0.10.14 · FC16 write to 40032–40033 from host outside authorized HMI subnet' }, { sev: "crit", rule: "IT-EX-07", title: "DNS tunneling — C2 signal", body: 'pkt #1053 · TXT query to atk.example · base64-shaped label, entropy 5.42 bits/char' }, { sev: "crit", rule: "WIFI-D-01", title: "802.11 deauthentication flood", body: 'pkt #1052 · BSSID aa:bb:cc:11 · 47 deauth/s for 4.2s — rogue-AP roaming attack' }, { sev: "crit", rule: "IT-ID-KRB", title: "Kerberoasting — high-rate TGS for SPNs", body: 'pkt #4102 · 23 TGS-REQ for MSSQL/backup SPNs from single host in 18s · RC4-HMAC encryption requested' }, { sev: "warn", rule: "IT-LM-11", title: "SMBv1 negotiation", body: 'pkt #1050 · 10.0.4.188 → 10.0.4.22 · SMB1 in dialect list — EternalBlue attack surface' }, { sev: "warn", rule: "WIFI-T-02", title: "Evil-twin candidate AP", body: 'pkt #2890 · SSID corp-guest broadcast from new BSSID outside known OUI range · RSSI consistent with same physical area' }, { sev: "warn", rule: "OT-ICSA", title: "ICS-CERT advisory match · Siemens S7-1500", body: 'pkt #5201 · S7comm session to 10.0.10.21 · firmware banner matches ICSA-25-038-01' }, { sev: "info", rule: "AI-LM", title: "Lateral movement: IT host → OT controller", body: 'pkt #2318 · 10.0.4.22 (laptop subnet, L4) initiated OPC-UA session to 10.0.10.21 (L2) · no baseline precedent in 14d' }]; const TAGLINES = { see_everything: { pre: "See everything.", main: "Understand", tail: "instantly.", sub: "Crafted to capture every packet. Engineered to explain it in your language. One install — IT, IoT, OT, and the air between them." }, full_spectrum: { pre: "Full-spectrum", main: "packet", tail: "intelligence.", sub: "Designed for forty protocols. Tuned for the boundaries where they meet. Local by default. Quiet until something speaks." }, wireshark_ai: { pre: "Wireshark", main: "with an", tail: "AI analyst.", sub: "Wireshark shows you everything. SPECTR tells you what matters." } }; /* icons */ const Icon = { capture: (p) => , detect: (p) => , brain: (p) => , lock: (p) => , shield: (p) => , offline: (p) => , github: (p) => , arrow: (p) => }; /* Chrome */ /* ── Logo ──────────────────────────────────────────────────── */ function Logo() { return ( SPECT R ); } /* ── Header ──────────────────────────────────────────────── */ function Header() { return (
Contact sales
); } /* ── Footer ───────────────────────────────────────────────── */ function Footer() { return ( ); } /* ── Tweaks panel — only used on home ──────────────────────── */ function TweaksPanel({ open, tagline, onTagline, heroVariant, onHero }) { if (!open) return null; return (
Tweakslive · persisted
{[ ["see_everything", "See everything. Understand instantly.", "On-brand, benefit-first"], ["full_spectrum", "Full-spectrum packet intelligence.", "Category-defining"], ["wireshark_ai", "Wireshark with an AI analyst.", "Comparative, pragmatic"]]. map(([k, label, note]) => )}
{[ ["centered", "Centered", "Headline-forward, demo below"], ["split", "Split", "Copy left, stream right"]]. map(([k, label, note]) => )}
); } /* ── Edit-mode hook for tweaks panel ──────────────────────── */ function useEditMode() { const [open, setOpen] = useState(false); useEffect(() => { function onMsg(e) { const d = e.data || {}; if (d.type === "__activate_edit_mode") setOpen(true); if (d.type === "__deactivate_edit_mode") setOpen(false); } window.addEventListener("message", onMsg); window.parent.postMessage({ type: "__edit_mode_available" }, "*"); return () => window.removeEventListener("message", onMsg); }, []); return [open, setOpen]; } function persist(key, value) { window.parent.postMessage({ type: "__edit_mode_set_keys", edits: { [key]: value } }, "*"); } /* Hero */ function PacketStream() { return (
SPECTR · live capture · en0
REC 1,770 pkts · 38 alerts
SPECTR live packet capture interface showing TLS, ARP, and UDP traffic with the AI Analyst panel surfacing lateral-movement and custom-rule findings on the right.
); } function Hero({ tagline, variant }) { const t = TAGLINES[tagline] || TAGLINES.see_everything; const copy = <>
SPECTR 0.6.0 · NET INTEL 1.7.0 · MACOS · WINDOWS · LINUX

{t.pre}
{t.main} {t.tail}

{t.sub}

47 protocols · IT + IoT + OT + Wi-Fi 34 anomaly rules · zero-latency Local AI · air-gap compatible Active throughput + perfSONAR drift correlation
; if (variant === "split") { return (
{copy}
); } return (
{copy}
); } function ProductCaption() { return (
Live capture

Crafted for microsecond detection. Composed for plain-English clarity.

The product, today. Live packet capture with the AI Analyst surfacing lateral movement, custom rules, and threats — in plain English, with the packets to back it up.

); } /* ProductSections */ function HowItWorks() { return (
The flow

Install. Capture. Ask.

Three commands. No agents. No cloud. Yours, end to end.

01 / CAPTURE

Point it at an interface or a PCAP.

Reads live from tshark on macOS and Windows, or opens any PCAP/PCAPNG. Drag-and-drop supported. First-run setup checks dependencies and exits with a specific error if something's missing.

# live capture
sudo spectr --iface en0
02 / DETECT

Rules fire on every frame. Zero latency.

Deep-parses 30+ protocols and evaluates a rule set across IT, IoT, and OT — unauthorized writes, lateral movement, DNS tunneling, SMBv1 negotiation, cross-domain flows, and more.

# tune per-environment
spectr rules enable OT-W-*
03 / ASK

Plain-English diagnosis with packet citations.

Ask the analyst why is this PLC getting writes from an unknown IP? — get a specific answer referencing packet IDs, IPs, function codes, and a recommended action. Runs against Claude or a local Ollama model.

# local inference
export INFERENCE_URL=http://localhost:11434/v1
); } function Coverage() { return (
Coverage

Every domain. One capture.

Designed for environments that never sit still. IT, IoT, OT, and Wi-Fi — parsed in a single stream. The traffic that crosses domains is usually the traffic worth watching.

{DOMAINS.map((d) =>
{d.label}{d.count}

{d.name}

{d.desc}

{d.protos.map((p) => {p})}
)}
); } function AnomalyShowcase() { return (
Detection

Specific findings. Not alert noise.

Crafted to cite the packet, the rule, the evidence. Every detection is inspectable. Every threshold is yours to tune.

{ANOMALIES.map((a, i) =>
{a.sev}
{a.title}
{a.rule}
)}
); } function NetworkGraphFeature() { const HUB = { x: 440, y: 270, label: "192.168.1.162", r: 22 }; const primary = [ { x: 200, y: 150, label: "224.0.0.251", dom: "iot", alert: true }, { x: 680, y: 130, label: "239.255.255.250", dom: "iot", alert: true }, { x: 160, y: 310, label: "192.168.1.188", dom: "it", alert: true }, { x: 285, y: 215, label: "192.168.1.144", dom: "it" }, { x: 320, y: 360, label: "192.168.1.106", dom: "it" }, { x: 380, y: 180, label: "162.125.21.2", dom: "it" }, { x: 565, y: 200, label: "142.251.179.94", dom: "it" }, { x: 600, y: 270, label: "35.186.224.24", dom: "it" }, { x: 760, y: 290, label: "17.253.12.93", dom: "it", warn: true }, { x: 520, y: 410, label: "104.17.132.16", dom: "it" }, { x: 360, y: 440, label: "74.125.139.180", dom: "it" }, { x: 250, y: 420, label: "52.110.2.139", dom: "it" }]; const secondary = [ [0, 130, 90], [0, 245, 75], [1, 750, 70], [1, 620, 60], [3, 215, 240], [5, 415, 105], [6, 540, 130], [7, 660, 215], [8, 830, 240], [8, 830, 330], [9, 595, 460], [10, 380, 490], [11, 175, 460]]; return (
Featured · the Network Graph

Unveil the blast radius — before you have to explain it.

The Network Graph reconstructs every IP conversation in your capture as a live force-directed graph. A flagged host isn't a single line in a log — it's a hub with primary connections (who it talked to directly) and secondary connections (who those hosts talked to in turn). One click on an alert tells you exactly how far the problem reaches.

Matched5
Blast radius55
Edges69
Packets2,139
); } function DeepAnalysisFeature() { return (
Featured · deep analysis

Ask once. Unveil everything — citation by citation.

Point SPECTR at a capture and ask it what's going on. The analyst reads the full session — flows, protocols, payload metadata — and returns a structured finding with the exact packet IDs, the risk, and a recommended action. No alert-list scrolling, no rule-ID decoding. Plain-English answers, packet-level evidence.

); } function AIIntelligence() { const caps = [ { t: "Plain-English investigation", b: "Ask the analyst anything about a packet, a flow, or the last hour. Every answer names the IPs, cites the packet numbers, and ends with a recommended next move." }, { t: "Natural-language packet search", b: "Skip the BPF. ‘Failed auth from the past hour.’ ‘Anything talking to a new external IP.’ The model writes the filter and applies it." }, { t: "PCAP comparison", b: "Two captures, one diff. New devices, new protocols, behavioral drift — surfaced as a structured before/after report." }, { t: "Per-device behavioral baseline", b: "Each device's normal — protocols, peers, rate envelopes — learned from observed traffic. Deviations show up where you're looking." }, { t: "MITRE ATT&CK mapping", b: "Every finding carries a MITRE technique ID — Enterprise for IT, ICS for OT. Your SOC tooling already speaks this language." }, { t: "JA3 / JA3S + JARM fingerprinting", b: "Every TLS handshake fingerprinted on the way in. Optional active JARM probes for C2 surface — admin-only, audit-logged, internal targets refused by default." }, { t: "ICS-CERT / CISA correlation", b: "OT devices in the capture matched against a local CISA advisory database. Hits appear inline. No internet required." }, { t: "Auto-summary on import", b: "Every PCAP that lands in the library — local, remote, or hand-carried — gets an AI summary in the background. Read the headline. Decide if it's worth a full investigation." }]; return (
The analyst

Designed to understand your network. Trained to explain it.

Orchestrated from behavioral truth, not statistical guesses. Every finding traces back to packets. Every model runs where you do.

{caps.map((c) =>

{c.t}

{c.b}

)}
); } function Compare() { const rows = [ ["Live capture + PCAP", "tick", "tick", "partial", "tick"], ["IT protocols (HTTP, TLS, DNS, SMB)", "tick", "tick", "tick", "partial"], ["IoT protocols (MQTT, CoAP)", "tick", "partial", "cross", "cross"], ["OT protocols (Modbus, DNP3, OPC-UA)", "tick", "partial", "cross", "tick"], ["Rule-based anomaly detection", "tick", "cross", "tick", "tick"], ["Plain-English AI diagnosis", "tick", "cross", "partial", "cross"], ["Runs air-gapped / local inference", "tick", "tick", "cross", "partial"], ["Single-command install", "tick", "tick", "cross", "cross"]]; const headers = ["", "SPECTR", "Wireshark", "SIEM", "OT-specific"]; const cell = (v) => { if (v === "tick") return ; if (v === "cross") return ; if (v === "partial") return partial; return v; }; return (
Against the field

Wireshark is powerful. A SIEM is generic. OT tools are siloed.

Crafted at the intersection. Packet-level depth. Real-time clarity. Every domain. One install.

{headers.map((h, i) =>
{h}
)}
{rows.map((r, i) =>
{r[0]}
{cell(r[1])}
{cell(r[2])}
{cell(r[3])}
{cell(r[4])}
)}
); } function Privacy() { return (
Privacy by design

Your packets stay on your network.

Most packet analysis tools ship your capture to their cloud. SPECTR doesn't. The default inference path is a local model — Ollama, LM Studio, or SGLang — running on the same machine.

Air-gap compatible
Zero outbound requests when configured with a local backend. Suitable for isolated OT networks and classified environments.
Payload redaction before prompt
Optional privacy layer strips credentials, tokens, and payload contents from the AI context window. Headers and metadata only.
Pluggable backend
Swap between Anthropic API, OpenAI, Gemini, and local models by changing one env var. No vendor lock.
); } /* BizSections */ function Compliance() { const fw = [ { k: "IEC 62443", d: "Zone/conduit analysis from captured traffic. Gap detection against IEC 62443 security requirements." }, { k: "NERC CIP", d: "Electronic Security Perimeter and CIP-007 monitoring evidence, generated from observed flows." }, { k: "NIST CSF 2.0", d: "Identify / Protect / Detect category mapping with finding citations." }, { k: "NIS2", d: "EU directive — incident reporting artifacts, asset coverage, detection evidence." }]; return (
Compliance

Four frameworks. One capture. No spreadsheets.

Orchestrated across IEC 62443, NERC CIP, NIST CSF 2.0, and NIS2. Delivered on your cadence. Audit-ready, every time.

{fw.map((f) =>
{f.k}

{f.d}

)}
); } function NetIntel() { const caps = [ { t: "5-vendor automation", b: "Cisco IOS / NX-OS, Arista EOS, Juniper JunOS, Fortinet. Forbidden-command regex + safe-command allowlist. AES-GCM credential vault — now covers SSH + SNMP v3 secrets." }, { t: "5 transports · Pattern C hybrid", b: "SSH (Netmiko) · NETCONF (ncclient) · Serial console (pyserial) · RESTCONF (urllib) · SNMP v2c + v3 USM (HMAC-SHA1/256 + AES-128/256). New per-device state_transport decouples config and state channels — SSH for diff/drift, SNMP for high-resolution counters." }, { t: "9 standard MIBs covered", b: "IF-MIB (HC 64-bit counters) · IP-MIB (ARP) · BRIDGE-MIB + Q-BRIDGE-MIB (MAC) · IP-FORWARD-MIB (routes) · LLDP-MIB (BFS picks up SNMP-only devices) · Q-BRIDGE-MIB (VLAN) · RSTP-MIB (STP) · ENTITY-MIB (SBOM). No vendor MIBs required." }, { t: "Auto-discovery + vendor fingerprint", b: "CDP/LLDP recursive crawl with Purdue-zone guard. New SNMP fingerprint endpoint pulls sysDescr / sysName / sysObjectID and classifies Cisco / Juniper / Arista / Fortinet / HP / Dell / Mikrotik from the enterprise-OID prefix." }, { t: "Config risk engine", b: "10 deterministic rules (SNMPv1, telnet, type-7, AAA gaps, ACL hygiene…) + optional LLM per-vendor analysis. Diff-aware findings auto-resolve when fixed. Encrypted-at-rest config snapshots (AES-GCM, reuses vault key)." }, { t: "Agentic troubleshoot", b: "7 protocol playbooks: BGP, OSPF, STP, VLAN, IP, OT, DHCP. 4 tools, 8-iter cap. Native tool-use across Anthropic / OpenAI / Gemini; structured-JSON fallback for local models." }, { t: "State discovery", b: "ARP / MAC / routes / BGP / OSPF / interface counters / VLAN / STP. Fleet-wide locators (“where is this MAC?”, “what's down?”) with longest-prefix-match routing." }, { t: "CVE + SBOM", b: "Local NVD SQLite mirror (air-gap default). CycloneDX 1.4 + SPDX 2.3. SNMP-only devices now emit SBOM via ENTITY-MIB. Grey-market serial detection. Boot-image drift via source-scoped finding diff." }, { t: "Topology + lifecycle", b: "Vendored Cytoscape map (3 layouts) with VLAN filter + STP overlay + 👑 root-bridge crown. Live flow overlays. Maintenance windows with pre/post safety snapshots. NERC CIP-010 PDF (deterministic SHA256 report-ID)." }, { t: "JSONL transcript logger", b: "Per-session request/response transcript across SSH / NETCONF / serial / RESTCONF. Atomic 0o600 file create, tenant-prefixed filenames, configurable retention (default 24h sweep), per-session size cap." }, { t: "Enterprise Devices grid", b: "Server-side filter / search / pagination. Bulk operations (200-device cap, no implicit cascade). Live /ws/netintel/devices WebSocket with online / stale / offline badges and row-pulse on events." }, { t: "1,522 tests · air-gap verified", b: "Net Intel sub-suite passing. SNMP secrets never appear in audit / response / error / log fixtures. Same Ed25519-signed JWT licensing as core; license modal shows live node usage and renewal prompts." }]; return (
Network Intelligence · separately licensed · Net Intel 1.7.0

Designed to read the network. Engineered to change it.

Net Intel adds active infrastructure discovery to SPECTR Five transports (SSH · NETCONF · Serial · RESTCONF · SNMP v2c/v3) across five vendors, the new Pattern C hybrid (SSH for configs + SNMP for state), nine standard MIBs covered with zero vendor-MIB dependencies, deterministic risk rules, agentic troubleshooting, CVE correlation, and SBOM — same air-gap, multi-tenant, license-gated posture as core SPECTR.

{caps.map((c) =>

{c.t}

{c.b}

)}
); } function Throughput() { const phases = [ { stage: "iPerf3", ver: "v0.5.3", bg: "var(--accent-blue)", tier: "Core SPECTR · Tools panel", t: "Active throughput testing", b: "New Throughput subtab next to Ping and Traceroute. TCP/UDP, reverse mode (download), 1–60s duration. Live canvas-rendered line chart of throughput-over-time. Color-coded summary cards: avg Mbps, retransmits, jitter, loss. Streaming text log for per-second forensic detail. Bundled iperf3 binary for macOS (Apple Silicon + Intel) and Windows; system $PATH fallback on Linux / Docker.", meta: "WebSocket-streamed · 71 tests · SPECTR_IPERF3_PATH override" }, { stage: "B0", ver: "v0.5.4", bg: "var(--accent-green)", tier: "Net Intel · SNMP fallback", t: "SNMP utilisation overlay", b: "Tier-0 fallback that needs no perfSONAR deployment. Green/amber/red colour band on every topology edge, computed from SNMP IF-MIB octet counter deltas (HC 64-bit preferred). Hover tooltip shows in/out percentages + absolute bps. Threshold bands at <50% / <80% / ≥80%; edges with insufficient data stay neutral.", meta: "?include=utilisation · +37 tests" }, { stage: "B1", ver: "v0.5.5", bg: "var(--accent-cyan)", tier: "Net Intel · perfSONAR clients", t: "pScheduler + esmond REST clients", b: "Stdlib-only urllib clients for perfSONAR's two REST APIs. Default OFF — quadruple env gate: ENABLED + PSCHEDULER_URL + ESMOND_URL + TRUSTED_HOSTS allowlist. Defense-in-depth PII redaction strips operator contact metadata from every response. URL allowlist re-checked at task-URL boundary. Optional bearer auth via API_KEY.", meta: "Air-gap default · +73 tests" }, { stage: "B2", ver: "v0.5.6", bg: "var(--accent-cyan)", tier: "Net Intel · perfSONAR overlay", t: "Measured throughput on the topology map", b: "Second \"perfSONAR\" toggle in the topology toolbar. Edges between registered testpoints paint by measured throughput / latency / loss from esmond's archive. Layers on top of B0: edges without perfSONAR data fall back to SNMP colour, so the operator always sees something. Hover shows \"perfSONAR: 942 Mbps · 1.23 ms · 0.01% loss\".", meta: "?include=perfsonar · +24 tests" }, { stage: "B3", ver: "v0.5.7", bg: "var(--accent-purple)", tier: "Net Intel · AI tools", t: "Historical questions to the analyst", b: "Agentic engine catalogue extends from 4 to 6 tools: query_perfsonar_latency and query_perfsonar_throughput. Ask \"what was latency between site A and B last Tuesday?\" or \"did congestion start after the config push?\" — the model picks the right tool, the right window, and answers in concrete numbers. Aggregate stats include count, avg, p50/p95/p99, max, min.", meta: "Up to 168h window · +39 tests" }, { stage: "B4", ver: "v0.5.8", bg: "var(--accent-red)", tier: "Net Intel · drift correlation", t: "Strategic differentiator", b: "When Net Intel detects config drift, the correlator automatically: reads pre-drift throughput + latency from esmond, schedules a fresh perfSONAR test on each affected path via pScheduler, polls until the run completes, re-reads esmond for post-drift, persists the before/after delta to the finding. The findings modal renders \"throughput: 1000.0 Mbps → 750.0 Mbps (Δ -25.0%)\" with green/red/muted colour coding past a 5% noise floor.", meta: "+24 tests · 1,742 Net Intel total" }]; return (
Throughput visibility · iPerf3 + perfSONAR

"Ping says good. The app feels bad." Now you can prove which.

Six features compose into a complete throughput-investigation workflow — from a one-shot iperf3 test in the Tools panel, to passive SNMP utilisation on the topology map, to perfSONAR-measured edges, AI-driven historical queries, and the differentiator: automatic before/after correlation when Net Intel detects config drift.

⚡ The differentiator
Config drift triggers a perfSONAR test. The delta is attached to the finding. When Net Intel sees a running-config change, the drift correlator auto-schedules a fresh throughput + latency measurement on every affected adjacency, then writes throughput: 1000 → 750 Mbps (Δ -25%) directly onto the drift finding. No other commercial network-monitoring tool does this. Air-gap safe; default off; opt-in via four env vars.
{phases.map((p, i) =>
{p.stage} {p.ver}
{p.tier}
{p.t}

{p.b}

{p.meta}
)}
An incident walks through every layer of the stack
  1. SNMP utilisation overlay paints the site-A → site-B edge amber. (B0 · passive)
  2. perfSONAR overlay confirms it's not a counter-flap — same edge paints red on measured throughput. (B2 · active)
  3. Operator asks the AI: "what was throughput last Tuesday?" Model calls query_perfsonar_throughput and answers. (B3 · historical)
  4. Drift correlator already attached throughput: 1000 → 750 Mbps (Δ -25%) to the change-window finding. (B4 · automatic)
  5. After the rollback, Tools → Throughput → one-shot iperf3 confirms the fix is live. (iPerf3 · verify)
); } function Enterprise() { const items = [ { t: "RBAC + audit log", b: "4 roles (superadmin / admin / analyst / viewer), JWT-gated REST + WebSocket, full audit trail. Opt-in — single-user mode stays simple." }, { t: "Multi-tenancy", b: "Tenant-scoped users, rules, schedules, and agents. Superadmin role for cross-tenant visibility. Built for MSSPs and multi-site teams." }, { t: "PCAP-over-IP remote agents", b: "Single-file standalone agent streams packets to a central server over an authenticated TCP channel. SHA256-hashed, tenant-scoped tokens." }, { t: "Custom rule builder", b: "9 fields × 16 operators. Build, test, and ship anomaly rules from the UI — no Python required. Live hit-counter via WebSocket; per-rule recent-matches view." }, { t: "Unified remote agent", b: "One spectr-agent binary. stream subcommand for live PCAP-over-IP; capture for time-boxed field collection with one-shot upload tokens. --save-only for air-gapped sites." }, { t: "Docker Compose self-host", b: "Multi-stage Dockerfile (non-root, tini PID 1, /data volume, EXPOSE 8765) + compose.yml with /api/auth/config healthcheck. Optional nginx TLS-termination block. SQLite + WAL backend; Litestream-ready." }, { t: "AI chat history", b: "Server-side persistence, tenant + user scoped, date-bucketed drawer. Resume any conversation. 90-day retention by default; opt-out via env." }, { t: "Hardened CORS + WS reconnect", b: "v0.4.7 audit closes the wildcard-CORS-with-credentials CSRF amplifier; WebSocket reconnect honours close codes (4401 auth / 4402 license / 4403 forbidden) and the 5-retry give-up. Capture state broadcasts authoritative running / last_error after every start/stop." }, { t: "Encrypted config snapshots", b: "AES-GCM at rest, reuses the credential vault key. Lazy decrypt with per-instance cache. SHA256 of plaintext keeps drift dedup unchanged. Superadmin migration endpoint for legacy rows. Vault-status banner re-arms on key rotation." }]; return (
Enterprise

Crafted for a single operator. Scaled for a practice.

Auth, RBAC, multi-tenancy, and remote capture — all optional, all backward-compatible with the single-operator default.

{items.map((i) =>

{i.t}

{i.b}

)}
); } function Pricing() { return (
Pricing

A foundation you own. An upgrade when you need it.

Packet Intelligence is licensed per analyst seat, per year. Network Intelligence — the active layer for the gear under your team's care — is licensed per managed node, per year, and available to any Packet Intelligence customer.

Both run in a single install. One stack. One license file.

Packet Intelligence
Contact sales
TBD/ year · per seat
Capture. Understand. Answer. The whole product, one install.
  • Live capture & the PCAP library. Open anything libpcap-aware. Re-analyze, compare, and export without re-running a session.
  • 47 protocol parsers. 29 IT · 9 OT/ICS · 3 IoT · plus the basics. OT is always routed first.
  • The AI analyst — local by default. Claude, Ollama, LM Studio, or SGLang. Cloud is an explicit choice, never the default.
  • 34 anomaly rules + a custom rule builder. MITRE ATT&CK mapped — Enterprise and ICS. Every finding cites the packet.
  • JA3 / JA3S · JARM · ICS-CERT correlation. TLS fingerprints and CISA advisories on the way in. Internet not required.
  • Behavioral baselines + Purdue zone mapping. What's normal per device, and what crossed a boundary it shouldn't.
  • Four compliance frameworks. IEC 62443, NERC CIP, NIST CSF, NIS2 — plus an executive summary, on your cadence.
  • Network Graph, sequence diagrams, draw.io export. Blast radius in one click. Reports your team can ship.
  • Distributed capture. Streaming agents, one-shot field tokens, or fully air-gap PCAPs — all into the same library.
  • Network tools, built in. Ping, traceroute, and bundled iPerf3. Throughput problems, proven.
  • Multi-tenancy, RBAC, audit log. Off for solo operators. Ready the day you scale.
  • macOS · Linux · Windows · Docker. Air-gap supported. 14-day trial, no card.
Contact sales
Network Intelligence
Per node
TBD/ year · per managed node
Active config / state / drift. SSH · NETCONF · Serial · RESTCONF · SNMP. Runs in the same install.
  • 5 vendors: Cisco IOS / NX-OS, Arista EOS, Juniper JunOS, Fortinet
  • 5 transports: SSH · NETCONF · Serial · RESTCONF · SNMP v2c/v3
  • Pattern C hybrid — SSH for configs + SNMP for state
  • Auto-discovery (CDP/LLDP) + SNMP vendor fingerprint endpoint
  • perfSONAR integration — utilisation overlay, measured overlay, AI tools
  • Drift correlation — auto pre/post throughput delta on config drift
  • Config risk engine — 10 deterministic rules + LLM per-vendor
  • Agentic troubleshoot — 7 playbooks + 6 tools (incl. perfSONAR)
  • CVE + SBOM (CycloneDX 1.4 / SPDX 2.3) · NERC CIP-010 PDF
  • Topology (VLAN · STP · 👑 root-bridge · utilisation · perfSONAR)
  • JSONL transcript · encrypted snapshots · maintenance windows · 1,742 tests
Contact sales
); } function Signup() { const [state, setState] = useState({ email: "", role: "", env: "", note: "", submitted: false, error: "", busy: false }); // Pick the API endpoint based on host. Override at runtime by setting // window.__SPECTR_API__ = "https://api.example.com" before bundle.jsx loads. const API_BASE = typeof window !== "undefined" && window.__SPECTR_API__ || ( typeof window !== "undefined" && /(^|\.)rex-labs\.tech$/.test(window.location.hostname) ? "https://api.rex-labs.tech" : ""); async function submit(e) { e.preventDefault(); if (!state.email || !state.email.includes("@")) { setState((s) => ({ ...s, error: "Enter a valid email address." })); return; } setState((s) => ({ ...s, busy: true, error: "" })); // Always stash locally as a fallback so we never lose a lead. try { const list = JSON.parse(localStorage.getItem("spectr_signups") || "[]"); list.push({ email: state.email, role: state.role, env: state.env, note: state.note, ts: Date.now() }); localStorage.setItem("spectr_signups", JSON.stringify(list)); } catch (_) {} // POST to the signup API. If the API isn't reachable we still show success // (the lead is in localStorage and the form is honest about reaching out). try { if (API_BASE) { const res = await fetch(API_BASE + "/api/signup", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: state.email, role: state.role, env: state.env, note: state.note, source: window.location.hostname, website: "" // honeypot }) }); if (!res.ok) { const j = await res.json().catch(() => ({})); setState((s) => ({ ...s, busy: false, error: j.error || "Could not send. Please try again or email spectr@rex-labs.tech." })); return; } } } catch (err) { setState((s) => ({ ...s, busy: false, error: "Network error. Please try again or email spectr@rex-labs.tech." })); return; } setState((s) => ({ ...s, submitted: true, busy: false, error: "" })); } return (
Early access

Join early.

Early adopter
Second year free for everyone who joins the list before GA. One year paid, one year on us — same product, same support, same license.

SPECTR 0.6.0 + Net Intel 1.7.0 are in late beta. Join the early-access list and we'll reach out with pricing, a demo, and a license for your environment. We don't blast — typically one email when there's something specific to share.

  • Pricing and per-seat / per-node terms
  • Live demo against your traffic profile
  • Air-gap deployment guidance
  • Or just early-access updates — your call
{state.submitted ?
You're on the list.
We'll reach out at {state.email}. Reply directly to that first email if you want to schedule a demo sooner.
: <>
setState((s) => ({ ...s, email: e.target.value, error: "" }))} />