Module: github.com/thathaneydude/unifi | Go: 1.26
A SemVer-versioned Go SDK and CLI for the official UniFi Network and
UniFi Protect integration APIs. Clients are generated from
OpenAPI specs with oapi-codegen, wrapped by a
thin hand-written layer that handles local and remote authentication, TLS options, and a
version-agnostic WebSocket layer for Protect real-time subscriptions. The same core powers a
spec-driven unifi CLI designed for LLM agents (JSON output, structured errors, runtime
discovery).
- Network: v10.3.58
- Protect: v7.1.46
- Docs: https://thathaneydude.github.io/unifi/
Download a prebuilt binary for your platform (macOS, Linux, Windows — amd64/arm64) from the
latest release, extract it, and put the
unifi binary on your PATH. Or install with Go:
go install github.com/thathaneydude/unifi/cmd/unifi@latest
go get github.com/thathaneydude/unifi@latest
package main
import (
"context"
"fmt"
"log"
"github.com/thathaneydude/unifi/unifi"
)
func main() {
// Connect directly to a console on the LAN.
// WithInsecureSkipVerify skips TLS verification for self-signed console certs.
c := unifi.Local("192.168.1.1", "your-api-key", unifi.WithInsecureSkipVerify())
network, err := c.Network()
if err != nil {
log.Fatal(err)
}
resp, err := network.GetInfoWithResponse(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.StatusCode())
}package main
import (
"context"
"fmt"
"log"
"github.com/thathaneydude/unifi/unifi"
)
func main() {
// Connect through the UniFi cloud connector using a console ID + API key.
c := unifi.Remote("your-console-id", "your-api-key")
protect, err := c.Protect()
if err != nil {
log.Fatal(err)
}
resp, err := protect.GetV1CamerasWithResponse(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.StatusCode())
}Status: in active development on
main.
The unifi CLI exposes every Network and Protect REST operation, generated at runtime from the
same OpenAPI specs that drive the SDK. Its primary user is an LLM agent that shells out to it,
so it defaults to machine-readable behavior:
- JSON by default on stdout (
--format humanfor a readable view,--format rawfor passthrough). - Structured errors on stderr with stable exit codes (
0ok,1usage,2auth,3API non-2xx,4transport). - Discovery built in:
unifi schemaandunifi <app> list-operations. - Safe writes: mutating operations support
--dry-runand require--confirm.
# Credentials via env (flags --host/--console-id/--api-key override)
export UNIFI_API_KEY=your-api-key
export UNIFI_HOST=192.168.1.1 # or UNIFI_CONSOLE_ID for remote
unifi protect list-operations # discover the surface
unifi protect GetV1Cameras # call an operation → JSON
unifi network getInfo --format human # human-readable viewNetwork and Protect mint separate integration API keys, so over the local transport each app needs its own key. Set both to drive both apps from one configuration:
export UNIFI_NETWORK_API_KEY=your-network-key # or --network-api-key
export UNIFI_PROTECT_API_KEY=your-protect-key # or --protect-api-key
unifi network getInfo # uses the Network key
unifi protect GetV1Cameras # uses the Protect keyEach app falls back to the shared UNIFI_API_KEY / --api-key when its app-specific key is unset,
so a single key still works for whichever app you target. (Over the remote transport, one
account-level Site-Manager key reaches both apps.)
The CLI also auto-loads a .env file from the working directory if present (use --env-file <path>
for a custom location). Real environment variables and flags take precedence, so the resolution order
is flags > environment > .env:
# .env in the current directory
UNIFI_API_KEY=your-api-key
UNIFI_HOST=192.168.1.1
unifi network getInfo # picks up .env automatically
unifi network getInfo --env-file ./prod.envA cloud account can hold several consoles. Enumerate them (needs only the account-level
UNIFI_API_KEY — no --console-id), then target one by name, model, or id:
unifi consoles list # id, name, model, ip per console
unifi consoles list --fields name,model # shape the listing like any result
unifi --console "Home" network getInfo # resolve a console by name → remote call
unifi --console-id <id-from-list> network getInfo # or pass the raw id directly--console resolves the name/model to the console id via consoles list (one lookup per run);
--console-id is the raw fast path. The id field from the listing is exactly what the remote
connector expects. The unifi-security-assessment skill uses this to let you pick which
console(s) to assess, writing one report per console.
Global flags reduce the shell glue agents otherwise need:
# Site resolution — most Network ops need a siteId. Omit it and the CLI uses the
# only site, or pass a name / "default" / id via --site (or UNIFI_SITE).
unifi network getNetworksOverviewPage # auto-selects the sole site
unifi network getNetworksOverviewPage --site default
# Terse discovery — no JSON parsing to find operation ids.
unifi network list-operations --ids # bare operation ids
unifi network list-operations --format human # aligned table + required params
# Response shaping (applied to JSON; --format raw stays verbatim).
unifi network getNetworksOverviewPage --fields name,vlanId # keep dot-path record fields
unifi network getNetworksOverviewPage --limit 5 # cap a result (or .data) array
unifi network getVpnServerPage --redact # mask secret-like fields as ***Required parameters (path and query) are validated up front, so an operation like
getFirewallPolicyOrdering reports its missing zone-id flags instead of failing at the API.
Realtime Protect subscriptions are intentionally SDK-only (see below), not exposed by the CLI.
The skills/ directory ships read-only Agent Skills
that drive the CLI to audit a UniFi deployment and produce a severity-ranked
findings report. The unifi-security-assessment orchestrator runs four focused
domain skills (unifi-network-security, unifi-segmentation-wifi,
unifi-asset-inventory, unifi-protect-security) as parallel subagents. They
never mutate configuration — only read-only operations are used, enforced by
just validate-skills.
See skills/README.md for installation and usage. In short:
# Install with the skills CLI (https://github.com/vercel-labs/skills)
npx skills add thathaneydude/unifi -g -a claude-code
# Then, with the unifi CLI on PATH and credentials set, ask your agent:
# "Run a UniFi security assessment of my deployment."
# → writes ./unifi-assessment-YYYY-MM-DD.mdFull documentation is published at https://thathaneydude.github.io/unifi/, including:
- Architecture and authentication design
- Getting started guide
- Go API reference (generated by
just docs-reference) - Network OpenAPI viewer and Protect OpenAPI viewer
- Decision records
Prerequisites: Go 1.26, just.
| Recipe | Description |
|---|---|
just sync |
Pull pinned upstream specs and apply overlays → specs/build/ |
just gen |
Regenerate clients and fakes from specs/build/ |
just build |
Compile all packages |
just lint |
go vet + golangci-lint |
just test |
Run unit suites with the race detector |
just test-e2e |
Run end-to-end suite (mock servers; real console when creds are set) |
just docs-serve |
Live-preview the docs site at http://127.0.0.1:8000 |
just docs-build |
Build the static docs site into ./site/ |
Run just with no arguments to list all available recipes.
This project is licensed under the MIT License.