Install
$ agentstack add skill-t3chnaztea-unifi-skills-unifi-clients ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
UniFi Clients and Devices
Day-to-day operations, and the two ways they go wrong: partial writes that silently destroy config, and VLAN changes that appear to work and do not.
Full-object PUT discipline
The rule that prevents most damage on this API:
> rest/* endpoints replace the object. GET it, modify the one field, PUT the > whole thing back.
A partial PUT does not merge. It writes what you sent and drops the rest. The consequences scale with the object:
rest/networkconf: PUT{"dhcpd_dns_1": "..."}and you can lose the network's
DHCP range, domain name, and VLAN assignment.
rest/wlanconf: you can lose the passphrase, the network binding, the band
settings.
rest/deviceport_overrides: PUT the completeport_overrideslist.
Sending one port's override resets every other port on the switch to defaults. On a 24-port switch carrying a segmented network, that is the whole afternoon.
# Correct shape, every time
udm raw GET /proxy/network/api/s/default/rest/networkconf/ > /tmp/net.json
# edit /tmp/net.json, changing only what you mean to change
udm raw PUT /proxy/network/api/s/default/rest/networkconf/ "$(cat /tmp/net.json)"
Then re-read and diff. The PUT response is not proof.
The wired VLAN migration trap
You change a switch port's native VLAN. The controller accepts it. The device behind that port is now stranded, and nothing tells you.
Changing native_networkconf_id in port_overrides does not bounce the link. The device never sees a carrier drop, so it never re-runs DHCP. It keeps its old-subnet lease, sits on a segment where that address has no gateway, and looks completely healthy until it needs to route somewhere. Then it fails in a way that looks like a firewall problem, which is where the afternoon goes.
Completing the move requires the device to issue a fresh DHCP DISCOVER, which means a real reboot. Lease expiry technically works and is useless: 24 hours.
PoE devices: force it cleanly over the API.
# Confirm the port actually draws power first
udm devices --json | python3 -c '
import json,sys
for d in json.load(sys.stdin):
for p in d.get("port_table") or []:
if float(p.get("poe_power") or 0) > 0:
print(d.get("name"), p.get("port_idx"), p.get("poe_power"))'
udm devices power-cycle
poe_power is a string ("0.00", "6.42"), not a number, so a truthiness test passes on an unpowered port. Cast it. The field is only present on switch (usw) port tables; APs and the gateway do not have it.
Full reboot, fresh DISCOVER, device lands on the new VLAN. Verify by reading its new address, not by assuming.
Self-powered devices cannot be force-renewed remotely. A link bounce makes them re-REQUEST their old lease (INIT-REBOOT), and when the new VLAN's DHCP server stays silent, they keep the stale address. There is no API path around this. The only reliable sequence:
- Flip the port to the target VLAN
- Physically power-cycle the device, unplug about ten seconds, replug
Zero-stranding variant, better if you are already standing there: unplug first, flip the port while it is off, replug. The device boots straight onto the new VLAN and is never stranded at all.
forward: 'disabled' is a no-op for disabling a port. Verified on UniFi OS 5.1.19 / Network 10.4.57: the controller accepts it, and the port stays UP. Do not build a "disable the port to force a renegotiation" plan on it.
Cosmetic, not a failure: after a non-default native assignment the controller normalizes forward from 'all' to 'customize' in the read-back. The port still passes native-VLAN traffic. Do not chase this.
Plan the order. If a batch contains both PoE and self-powered devices, do the PoE ones over the API and leave the self-powered ones for when you can physically reach them. Do not flip a self-powered device's port and walk away: leaving a security device, camera, or alarm component stranded offline is worse than not having started. Revert the port if the physical trip is not happening today.
Client operations
udm clients # currently connected
udm clients --all # including offline, the full known list
udm clients block
udm clients unblock
udm clients kick # force reassociation
kick is the gentle diagnostic: it makes a client re-associate, which re-runs band steering and AP selection. Useful when a device is stuck on a distant AP.
Forgetting stale clients. The known-client list accumulates forever. Old reservations for decommissioned hardware, VM interfaces, replaced phones:
udm raw POST /proxy/network/api/s/default/cmd/stamgr \
'{"cmd":"forget-sta","macs":[""]}'
Worth a periodic sweep. A reservation table full of dead entries is where a stale DHCP reservation quietly hands a live device the wrong address, and it makes the inventory in unifi-context-map much harder to keep honest.
Reservations are not reality. A fixed-IP reservation only applies if the device asks that DHCP server. A camera with a reservation on the camera VLAN that actually joins over Wi-Fi to the IoT SSID gets an IoT address, and the reservation sits dormant looking authoritative. Always confirm from the live client list where a device actually is, not from the reservation table.
udm reservations --json | python3 -c '
import json,sys
for u in json.load(sys.stdin):
print(u.get("name") or u.get("hostname"), u.get("fixed_ip"), u.get("mac"))'
Device operations
udm devices # all adopted devices
udm devices restart
udm devices provision # force-provision, push config
udm devices power-cycle # PoE port on a switch
provision is the right first move when a device's operational state disagrees with its config. It is also how you confirm a setting genuinely is not applying: if two force-provisions do not change operational behavior, the hardware does not support what you are asking. That is how the in-wall AP port limitation in unifi-wifi was established.
DHCP DNS
Set on the network object, so full-object PUT applies:
udm raw GET /proxy/network/api/s/default/rest/networkconf/
# fields: dhcpd_dns_1, dhcpd_dns_2, dhcpd_dns_3
Practical notes: make all your LAN networks agree unless you have a specific reason not to, or a device's filtering depends on which VLAN it happens to be on. If you run a filtering resolver, give clients a second one on different hardware, because a DNS resolver on a single box is a single point of failure for the entire network's usability. Pointing the last entry at the gateway gives you an unfiltered last resort, which is either a safety net or a filtering bypass depending on what the resolver is for. Choose deliberately.
Clients keep their old DNS servers until their lease renews. Changing this and testing immediately from an already-connected machine tests nothing.
Events and alarms
Legacy stat/event 404s on Network 10.4. Events moved to v2, and it is a POST with a pagination body:
udm events # POST /v2/api/site/default/system-log/all
udm events --pages 5 # page back further
udm alarms # unresolved
udm alarms archive
udm alarms archive-all
Alarms are worth reading before any change session: an existing alarm about an adoption failure or a switch uplink explains symptoms you would otherwise blame on your own change.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: t3chnaztea
- Source: t3chnaztea/unifi-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.