TypeScript/Bun CLI for the AT&T BGW320 gateway at 192.168.1.254.
Setup
bun installGlobal Install
This package exposes the bgw executable:
bgw --helpFor local development from this checkout:
bun link
bgw --helpIf you previously linked the old package name, remove it first:
bun unlink bgw320-cli
bun linkAfter publishing to a registry, install globally with Bun:
bun add -g bgwThe CLI depends on Bun because the executable points at TypeScript source with a Bun shebang.
Agent Skill
This repo includes a Codex/OpenAI skill in skills/network-management/SKILL.md. When using an agent that supports local skills, point it at the skill/ folder so it can use the bundled safety model, command map, and inspection notes for bgw.
Quality Checks
bun run typecheck
bun test
bun run lint
bun run deadcode
bun run unused-exports
bun run exports
bun run doctordoctor is the default one-command local health check for this CLI. It runs typecheck, tests, ESLint, Knip, and publint.
Usage
bgw check
bgw coverage
bgw sweep --pages diag,dhcpserver --json
bgw audit
bgw tabs
bgw section Diagnostics
bgw broadband fiber-status
bgw home-network wi-fi --json
bgw home-network advanced-wi-fi --json
bgw firewall nat-gaming
bgw diagnostics logs --limit 50Authenticated pages require the device access code. Prefer stdin so the code is not stored in shell history:
printf '<access-code>' | bgw auth --access-code-stdin
printf '<access-code>' | bgw wifi --access-code-stdinBGW_ACCESS_CODE is also supported for automation.
Commands
| Command | Purpose |
|---|---|
check | Verify the router is reachable. |
auth | Verify the access code and session login flow. |
tabs | Print the CLI's router tab map. |
actions | List guarded router actions and confirmation tokens. |
action <name> | Dry-run a guarded router action. Requires --commit --confirm TOKEN to POST. |
section <section> | Print mapped tabs for one router section. |
coverage | Compare the CLI tab map against the live router sitemap. |
sweep | Shared traversal command for mapped router pages. Default output is compact status/count metadata. |
scan | Compatibility alias for compact sweep metadata. |
schema | Sweep with parsed/form detail enabled. |
audit / readiness | Sweep-backed health check that keeps going through hangs and summarizes failed/fallback/empty/useful pages. |
sitemap | Print the live router sitemap. |
page <page-or-tab> | Fetch and parse any mapped tab or raw CGI page ID. |
inspect <page-or-tab> | Fetch a page and include parsed form fields/selects. |
status | Fetch the core status pages. |
devices | List current and remembered devices; status comes from the gateway and may be stale. |
wifi | Fetch Wi-Fi configuration with secrets redacted by default. |
nat | Fetch NAT table details. |
logs | Fetch router logs. |
set <page> KEY=VALUE... | Build a dry-run mutation plan. Requires --commit to POST. |
submit <page> <button> KEY=VALUE... | Build a dry-run form/button submission. Requires --commit --confirm TOKEN to POST. |
Router Command Tree
All of these commands accept --json. Parsed page JSON includes a summary object with the same high-value fields used by the terminal view, plus the underlying values, tables, controls, buttons, and forms. Use --forms to include form controls in normal terminal output.
bgw device status
bgw device device-list
bgw device system-information
bgw device access-code
bgw device remote-access
bgw device restart-device
bgw broadband status
bgw broadband configure
bgw broadband fiber-status
bgw home-network status
bgw home-network configure
bgw home-network ipv6
bgw home-network wi-fi
bgw home-network advanced-wi-fi
bgw home-network mac-filtering
bgw home-network subnets-dhcp
bgw home-network ip-allocation
bgw voice status
bgw voice line-details
bgw voice call-statistics
bgw firewall status
bgw firewall custom-services
bgw firewall packet-filter
bgw firewall nat-gaming
bgw firewall public-subnet-hosts
bgw firewall ip-passthrough
bgw firewall firewall-advanced
bgw firewall security-options
bgw diagnostics troubleshoot
bgw diagnostics ping example.com
bgw diagnostics ping example.com --commit --confirm DIAG
bgw diagnostics traceroute example.com --commit --confirm DIAG
bgw diagnostics nslookup example.com --commit --confirm DIAG
bgw diagnostics speed-test
bgw diagnostics logs
bgw diagnostics update
bgw diagnostics resets
bgw diagnostics syslog
bgw diagnostics event-notifications
bgw diagnostics nat-tableGeneric Inspection And Forms
Use inspect or --forms when the router page changed and you need to see what the CLI discovered:
bgw inspect "Diagnostics/Troubleshoot" --forms
bgw home-network wi-fi --formsReadable page output shows available buttons and control counts by default. JSON includes parsed values, duplicate-preserving valueEntries, tables, fields, select option labels/state, textareas, buttons, forms, links, and disabled/readonly metadata. Use --forms to show those preserved details in terminal output.
Several configuration pages have page-specific summaries built from current form state so default terminal output stays useful:
broadband configure: source override and MTU values.device access-code,device remote-access,device restart-device: current form/action state with sensitive values redacted and restart surfaced as an explicit guarded action.home-network configure,home-network ipv6,home-network wi-fi,home-network advanced-wi-fi,home-network mac-filtering: compact current network form state, including per-port configured Ethernet modes, basic current channel rows, advanced radio/SSID controls, and per-radio MAC-filter state. Passwords, SSIDs embedded as defaults, and WPS PINs stay redacted in fixtures.home-network subnets-dhcp: gateway/subnet, DHCP range, lease, public subnet, inbound, and cascaded-router state.firewall packet-filter,firewall custom-services,firewall nat-gaming,firewall public-subnet-hosts: current firewall/NAT form state; NAT/Gaming shows selected service/device and available service/device counts instead of dumping every dropdown option.firewall ip-passthrough: allocation mode, default server, passthrough mode/MAC, and lease.firewall firewall-advanced: ICMP, Reflexive ACL, ESP ALG, and SIP ALG toggles.diagnostics update,diagnostics resets,diagnostics event-notifications: current action/form state without requiring browser clicks.
Pages on this router can hang. Normal parsed page commands report a structured page-unavailable result instead of taking down broader workflows. scan, schema, and audit continue across failures so one broken AT&T page does not hide the rest of the router.
Sweep
sweep is the shared traversal spine used by scan, schema, audit/readiness, and fixture capture. It uses one client/session, walks mapped pages in router-tab order, keeps going through per-page failures, and reports compact counts by default.
bgw sweep
bgw sweep --json
bgw sweep --pages diag,wconfig_unified,dhcpserver --json
bgw sweep --include-parsed --json
bgw sweep --forms --json
bgw sweep --out router-dumps/latestDefault sweep output does not dump raw HTML or full parsed payloads. It reports counts for unique values, duplicate-preserving value entries, tables, controls, forms, and links. Use:
--include-parsedfor parsed values, value entries, tables, fields, select option metadata, textareas, buttons, forms, links, fallback sections, and device-list fallback data in JSON.--formsfor detailed controls, buttons, forms, and submit targets.--pages <csv>to limit traversal.--raw --pages <single-page>to emit one raw HTML page.--out <dir>to write raw HTML and parsed JSON artifacts to disk while keeping stdout compact.
scan is retained as the compatibility command for compact sweep metadata. schema is sweep with parsed/form detail. audit and readiness are sweep plus the health/usefulness summary.
device status first tries home.ha. If that page hangs, it falls back to a concise summary from System Information, Broadband Status, and Firewall Status. Use the section-specific commands for deeper output such as broadband fiber-status or home-network status.
devices first tries devices.ha. If that page hangs, it falls back to ipalloc.ha and returns degraded device records with IP, name, MAC, status, and allocation. The primary page can also expose connection speed and IPv6 lifetime fields, but it does not establish disconnect history, stable identity across private MAC addresses, or trustworthy user-assigned names. Treat last activity as a timestamp reported by the gateway, not proof of a disconnect.
The unified Wi-Fi page exposes configured SSIDs, enabled state, security controls, isolation, and current channel/width rows on firmware that renders them. When the 5 GHz row reports two channels, the CLI labels them low-band and high-band using their channel ranges; that radio split is locally derived while the channel numbers remain router-reported. The linked Advanced Wi-Fi page adds standards, configured bandwidth/channel selection, power, maximum clients, hidden SSID, WPA/WPS state, and separate private/guest controls, but its observed 5 GHz controls are combined rather than independent per-radio settings.
Neither observed Wi-Fi page provides client RSSI, noise floor, retry counts, association/roaming history, disconnect events, or enough evidence to diagnose RF health or congestion. Channel-selection, WPS, update, and save buttons are mutating controls and are never invoked by read commands.
broadband fiber-status preserves router-reported optical receive/transmit power, temperature, voltage, bias, operational state, and alarm thresholds when present. Values and units are passed through as reported; the CLI does not infer optical health or service quality from them. voice call-statistics preserves all observed line, summary, and cumulative rows while caller/phone fields stay redacted by default.
home-network status first tries lanstatistics.ha. If that page hangs, it falls back to LAN configure, Subnets & DHCP, IP Allocation, and Wi-Fi configuration data.
firewall security-options first tries securityoptions.ha. On firmware that advertises that page but returns Page not found, it falls back to Firewall Status and Firewall Advanced.
The router can also refuse login when its tiny web session pool is full. By default the CLI fails fast with a clear error so normal commands do not appear hung. To wait only for that exact condition:
printf '<access-code>' | bgw sweep --wait-for-session --access-code-stdin
printf '<access-code>' | bgw sweep --wait-for-session --session-wait-timeout 120000 --session-wait-interval 10000 --access-code-stdinEnvironment equivalents:
BGW_WAIT_FOR_SESSION=1
BGW_SESSION_WAIT_TIMEOUT_MS=120000
BGW_SESSION_WAIT_INTERVAL_MS=10000Waiting does not retry bad access codes, random connection failures, or parser failures. An active five-minute local pool cooldown still fails fast with --wait-for-session; do not clear it simply to force another authentication attempt. bgw session clear-cache acquires the same per-router lock and is intended only for explicit local-state troubleshooting.
Router Fixture Pack
Parser ground truth belongs under:
tests/fixtures/router-html/<page>.html
tests/fixtures/parsed/<page>.json
tests/fixtures/expected/<page>.jsonGenerated fixture files are gitignored on purpose. They are sanitized, but they can still reveal local topology, device names, firmware behavior, and configuration shape. Keep them local unless you have manually reviewed them.
Capture sanitized fixtures from the real router with:
BGW_ACCESS_CODE='<access-code>' bun run fixtures:captureThe capture is sweep-backed, serialized through the same per-router session coordinator, paced at no less than 750 ms between pages, and read-only at the configuration level: it performs GET requests plus the login POST required by the router. It redacts access-code-adjacent fields, Wi-Fi identifiers, device identifiers, hashes, MAC addresses, and IP addresses before writing owner-only fixture files.
tests/router-fixtures.test.ts verifies that a complete 37-page fixture pack covers every mapped page, that parsing the saved HTML exactly matches the saved parsed JSON, and that each expected file records value/value-entry, table, control, form, link, redaction, and non-junk parsing receipts.
Diagnostics
Diagnostic network actions dry-run by default and require --commit --confirm DIAG to send the router form:
bgw diagnostics ping example.com
bgw diagnostics ping example.com --commit --confirm DIAG
bgw diagnostics traceroute example.com --commit --confirm DIAG
bgw diagnostics nslookup example.com --commit --confirm DIAGUse --ipv4 or --ipv6 to set the router protocol preference.
Safety
Read commands only send GET requests plus the login POST required for authenticated pages.
set defaults to dry-run. Every actual POST requires --commit --confirm TOKEN; the token is derived from the target CGI page, such as WCONFIG-UNIFIED for Wi-Fi.
action defaults to dry-run. Actual action POSTs require --commit --confirm TOKEN; run actions to see tokens.
submit defaults to dry-run. It fetches the page, discovers the requested button, builds the router POST payload from the current form state plus your overrides, and prints the confirmation token:
bgw submit "Diagnostics/Troubleshoot" Ping Address=example.com
bgw submit "Diagnostics/Troubleshoot" Ping Address=example.com --commit --confirm DIAGGeneric submit is blocked on dangerous pages such as restart/reset/update/access-code. Use an explicit supported action for those.
Dry-run JSON for action, set, submit, and diagnostic commands uses the same operation shape:
{
"operation": "action",
"dryRun": true,
"committed": false,
"page": "speed",
"guarded": true,
"dangerous": false,
"confirmation": "SPEED",
"commitCommand": "action run-speed-test --commit --confirm SPEED",
"payload": { "run": "Run Speed Test" }
}The generic set command refuses mutation attempts against dangerous pages:
routerpasswdrestartresetupdate
Supported explicit actions are guarded separately. Current action commands:
bgw action restart
bgw action clear-device-list
bgw action run-speed-test
bgw action run-full-diagnostics
bgw action send-diagnostics
bgw action diagnostics-ethernet-details
bgw action diagnostics-authentication-details
bgw action diagnostics-ip-details
bgw action diagnostics-dns-details
bgw action packet-filter-enable
bgw action packet-filter-add-drop-rule
bgw action packet-filter-add-pass-rule
bgw action reset-ip
bgw action reset-connection
bgw action restart-from-resets
bgw action reset-wifi-config
bgw action reset-firewall-config
bgw action factory-resetEvery action command is dry-run by default. actions prints the confirmation token required to commit each one. Reset/restart/factory-reset actions are marked dangerous and should be treated as destructive router operations.
Sensitive values are redacted by default. Use --include-secrets only when intentionally inspecting local output. Debug/schema output still redacts secrets by default.
The router normally presents a self-signed certificate, so the CLI currently accepts it by default. This encrypts traffic without proving router identity; use --strict-tls only after installing or pinning a certificate that the runtime can validate, and otherwise run the CLI only from a trusted local network.
Router Tab Coverage
The local registry contains the 36 observed sitemap pages plus the linked read-only wconfig Advanced Wi-Fi endpoint, for 37 mapped pages total. coverage reports sitemap differences explicitly, so the linked endpoint can appear under “Not in live sitemap” without being treated as missing.
The implementation and capability reconciliation, including product-guide-only hardware features and observed-firmware limitations, is recorded in docs/FUNCTIONALITY_COVERAGE_REVIEW.md.
If a router page hangs or changes, use:
bgw audit
bgw scan --json
bgw inspect "Home Network/Wi-Fi" --forms