unifi-channel-planning
Skill294 starsChanged 18 days agoApache-2.0View on GitHub
Build an AI-driven low-interference WiFi channel plan from UniFi MCP neighbor observations. Use when the task is RF optimization, channel conflict reduction, co-channel interference mitigation, or per-AP channel assignment.
We split this skill into the rules it gives an agent
49 rules. About 0 are common, 33 are distinctive, and 16 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈33
Distinctive · estimate
This author's own choices. Worth a look.
16
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 11
Use this skill to produce a deterministic channel plan from MCP output.
- Distinctive: line 16
Keep assignments reproducible and explainable.
- Distinctive: line 53
If any field is missing:
- Distinctive: line 56
Do not use records without a band/radio dimension for channel assignment.
- Distinctive: line 57
Keep records without width only for a conservative 20 MHz fallback and mark the affected recommendation medium-confidence.
- Distinctive: line 59
Keep processing with partial data and log dropped count.
- Distinctive: line 63
Use two distinct datasets and do not mix them:
- Distinctive: line 76
Use only as additional congestion context, not as the internal AP graph.
- Distinctive: line 80
Keep the MCP interaction bounded and return summaries rather than raw payloads:
- Distinctive: line 82
Use a fixed planning window, normally 24 hours.
- Very specific: line 86
Prefer list_site_internal_ap_neighbors_v2 because it aggregates the per-AP v2 calls server-side.
- Very specific: line 91
Call list_neighboring_aps only when external RF pressure is needed for a tie-breaker or explanation.
- Distinctive: line 100
If a response is still too large, process APs or pages in deterministic batches and merge the normalized results before optimization.
- Distinctive: line 111
When physical AP locations are unavailable:
- Distinctive: line 113
Do not block planning on a floor plan, coordinates, or manually supplied zones.
- Distinctive: line 115
Use the normalized internal v2 graph as the measurable overlap proxy: observed AP pairs, RSSI, freshness, band, channel, and width.
- Distinctive: line 117
Do not claim that two APs are physically distant or in separate areas unless that is reported by UniFi or supplied by the operator.
- Distinctive: line 121
Prefer no-op or small staged changes when the graph is sparse.
- Very specific: line 135
Before scoring, convert every UniFi radio configuration into a canonical occupied_20mhz_channels set.
- Very specific: line 137
Do not infer occupied blocks solely from a numeric primary channel.
- Distinctive: line 139
If UniFi does not provide enough information to determine occupied 20 MHz blocks unambiguously, mark the radio medium-confidence and use …
- Very specific: line 145
Default threshold: keep neighbors with signal >= -85.
- Distinctive: line 160
Use deterministic greedy global optimization: assign the next most constrained AP, then recompute the complete graph score after each …
- Distinctive: line 173
Use ascending channel order as the final deterministic tie-breaker.
- Distinctive: line 194
Use deterministic RSSI weight classes instead of assuming a linear RF effect:
- Distinctive: line 204
Before optimization, normalize the internal graph:
- Distinctive: line 206
Treat AP-A seeing AP-B and AP-B seeing AP-A as one undirected physical pair.
- Distinctive: line 208
Use the most recent valid RSSI per undirected pair, retaining band and width separately.
- Very specific: line 211
Never infer the observer's current channel from the channel field: it is the observed neighbor/BSSID channel only.
- Distinctive: line 214
Do not sum an observer's neighbor rows against a candidate while leaving all other APs at their current channels.
- Distinctive: line 220
Avoid changing all APs at once.
- Distinctive: line 221
Keep at least one stable channel anchor per area.
- Very specific: line 224
When topology and RF scores permit, prefer a balanced channel population.
- Distinctive: line 227
Treat a mathematically lower score that moves many APs or abandons a channel as a candidate for staged review, not as an automatic rollout.
- Very specific: line 266
Run list_sites and select site_id.
- Very specific: line 269
If needed, inspect problematic APs with list_ap_neighbors_v2.
- Distinctive: line 284
Wait validation window and compare client health/events.
- Distinctive: line 285
If AP instability or client disconnects exceed the configured threshold, restore the persisted settings before continuing.
- Distinctive: line 295
After each rollout wave, verify:
- Distinctive: line 300
No AP is assigned unsupported channel width/channel pair.
- Very specific: line 305
Treat channel=auto as unknown current state.
- Distinctive: line 312
Read the observer's current channel from AP radio configuration or telemetry.
- Very specific: line 318
If internal graph is empty, do not derive channel plan from rogueap alone.
- Distinctive: line 331
If neighbor dataset is empty for a site, do not auto-assign.
- Very specific: line 332
If an AP has no observations, keep current channel and mark low confidence.
- Very specific: line 333
If an AP is configured as Auto and its current channel is inferred from a fresh neighbour observation, preserve the original Auto setting …
- Very specific: line 337
If list_site_internal_ap_neighbors_v2 reports skipped_aps, keep those APs unchanged and mark low confidence.
- Very specific: line 338
If only rogueap is available and internal AP graph is missing, return "insufficient internal data" instead of proposing deterministic …
- Very specific: line 339
If the current configuration is already within the accepted score tolerance, return a valid no-op plan with 0 APs changed.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
UniFi Channel Planning
Use this skill to produce a deterministic channel plan from MCP output.
Primary intent:
- Reduce overlap and co-channel contention.
- Keep assignments reproducible and explainable.
- Provide safe change rollout with validation.
Required MCP Inputs
| Tool | Purpose |
list_sites | Select target site |
list_devices_by_type | Get managed AP inventory (type=uap) |
list_site_internal_ap_neighbors_v2 | Build internal AP-to-AP graph for one site in one call |
Conditional / Optional MCP Inputs
| Tool | When to use |
list_neighboring_aps | Optional external RF tie-breaker or explanation; do not fetch by default |
list_ap_neighbors_v2 | Per-AP drill-down, debugging, or partial-result validation |
get_device_details | When radio configuration, current channel, width, or regulatory capabilities are not available from inventory |
Optional execution tool:
| Tool | Purpose |
set_ap_radio_channel | Apply proposed channel per AP/radio |
Data Contract For Planning
Expected fields from neighbor observations:
ap_mac: AP that observed the neighborbssidormac: observed AP/BSSID identitychannel: observed neighbor channel numbersignal: RSSI (dBm)last_seen: freshness indicatorradioorband: required radio/band dimension (ng/2.4 GHz orna/5 GHz)channel_widthorht: channel width, required when available for 5 GHz
If any field is missing:
- Drop records without
ap_mac,channel, orsignal. - Do not use records without a band/radio dimension for channel assignment.
- Keep records without width only for a conservative 20 MHz fallback and mark the affected recommendation medium-confidence.
- Keep processing with partial data and log dropped count.
Correct Data Source Split (Critical)
Use two distinct datasets and do not mix them:
- Internal AP-to-AP graph (for channel assignment):
- Primary source:
list_site_internal_ap_neighbors_v2(site_id, start_ms, end_ms, min_rssi) - The tool already executes v2 per-AP neighbor queries and keeps only rows where neighbor
macis a managed AP MAC from the same site. - Optional fallback/debug:
list_ap_neighbors_v2per AP. - This is the authoritative input for "which site AP sees which other site AP and how strong".
- External RF pressure (optional tie-breaker):
- Source:
list_neighboring_aps(stat/rogueap) - Represents foreign BSSIDs around the site.
- Use only as additional congestion context, not as the internal AP graph.
Data Volume Controls
Keep the MCP interaction bounded and return summaries rather than raw payloads:
- Use a fixed planning window, normally 24 hours; shorten it when the graph or response is too large.
- Pass
min_rssiduring collection (-85by default,-80for dense sites) instead of collecting all weak observations and filtering after output. - Prefer
list_site_internal_ap_neighbors_v2because it aggregates the per-AP v2 calls server-side. Do not repeatlist_ap_neighbors_v2for every AP unless debugging a specific AP or validating a partial result. - Request AP inventory with an explicit
limitandoffsetwhen supported; continue in pages until the managed AP set is complete. - Call
list_neighboring_apsonly when external RF pressure is needed for a tie-breaker or explanation. It can contain hundreds of rows and must never be dumped into the planning response by default. - Normalize, deduplicate, score, and sort before presenting results. Return metadata, counts, top conflict drivers, and a compact per-AP summary instead of raw JSON.
- Cap displayed neighbors per AP to the strongest relevant observations and report the total count plus omitted-row count. Offer per-AP drill-down only on request.
- If a response is still too large, process APs or pages in deterministic batches and merge the normalized results before optimization; never silently truncate the graph.
Required collection metadata:
start_ms,end_ms, andmin_rssi- managed AP count and collected edge count
- dropped, skipped, paged, and omitted-row counts
- whether external rogue-AP data was collected
When physical AP locations are unavailable:
- Do not block planning on a floor plan, coordinates, or manually supplied zones.
- Use the normalized internal v2 graph as the measurable overlap proxy: observed AP pairs, RSSI, freshness, band, channel, and width.
- Do not claim that two APs are physically distant or in separate areas unless that is reported by UniFi or supplied by the operator.
- Lower confidence for conclusions that depend on unobserved coverage or client roaming between APs.
- Prefer no-op or small staged changes when the graph is sparse; the planner may still produce a deterministic plan from the telemetry that is available.
Planning Rules
- Scope by band:
- 2.4 GHz candidates: channels 1-14 (practical non-overlap: 1, 6, 11)
- 5 GHz candidates: local policy set (for example 36/40/44/48 and DFS set if allowed).
- Plan each band/radio independently. Never score a 2.4 GHz observation against a 5 GHz candidate or use one band to fill missing data in the other.
- Derive occupied channel ranges from primary channel and width. For 20 MHz, use one channel block; for 40/80 MHz, include every overlapping 20 MHz block in the configured channel range.
- Before scoring, convert every UniFi radio configuration into a canonical
occupied_20mhz_channelsset. - Do not infer occupied blocks solely from a numeric primary channel. Use the UniFi-reported primary/control/center channel and width representation.
- If UniFi does not provide enough information to determine occupied 20 MHz blocks unambiguously, mark the radio medium-confidence and use the conservative supported interpretation.
- Filter weak observations:
- Default threshold: keep neighbors with
signal >= -85. - For dense environments, use
>= -80.
- Build per-AP conflict score:
- For each AP and candidate channel, sum weighted conflicts from observed neighbors on same or overlapping channels.
- Stronger RSSI contributes higher penalty.
- Internal AP-to-AP penalties must be weighted higher than external rogue BSSID penalties.
- Deterministic assignment:
- Sort APs by descending neighbor pressure (most constrained first).
- Evaluate assignments against the complete internal AP graph, not each AP in isolation. Re-score all graph edges after every proposed assignment so a locally good choice cannot create a global co-channel cluster.
- Use deterministic greedy global optimization: assign the next most constrained AP, then recompute the complete graph score after each assignment.
- Select the candidate with the lowest total graph penalty. Use descending pressure and ascending channel order as deterministic tie-breakers.
- Tie-breaker order must be fixed (for example ascending channel number).
Optimization order is strict:
- Minimize the complete RF conflict score.
- Among equivalent or near-equivalent scores, minimize channel concentration
and prefer a balanced population such as
3/3/2for eight APs on three 2.4 GHz channels. - Minimize the number of changes.
- Use ascending channel order as the final deterministic tie-breaker.
Default score tolerance:
- Relative tolerance:
2% - Absolute tolerance:
0.01 - A candidate is near-equivalent when
candidate_score <= best_score * 1.02orcandidate_score - best_score <= 0.01.
For a global 2.4 GHz assignment, score every internal edge using the proposed channels of both APs:
- Same channel:
rssi_weight(signal) - Adjacent 2.4 GHz channel:
0.5 * rssi_weight(signal) - Non-overlapping channel:
0
For 5 GHz, score overlap between the occupied channel ranges. A shared 20 MHz block receives the same base penalty, scaled by the fraction of overlapping blocks. An 80 MHz AP therefore contributes more spectrum pressure than a 20 MHz AP when the ranges overlap.
Use deterministic RSSI weight classes instead of assuming a linear RF effect:
signal >= -55: weight4.0-65 <= signal < -55: weight3.0-75 <= signal < -65: weight2.0-85 <= signal < -75: weight1.0
Multiply same-channel or overlap penalties by this weight. Keep the raw RSSI in the output reason so the score remains explainable.
Before optimization, normalize the internal graph:
- Treat AP-A seeing AP-B and AP-B seeing AP-A as one undirected physical pair.
- Deduplicate repeated observations within the planning window.
- Use the most recent valid RSSI per undirected pair, retaining band and width separately. A configurable freshness window may retain the strongest valid observation as secondary context, but must not replace the current value.
- Never infer the observer's current channel from the
channelfield: it is the observed neighbor/BSSID channel only.
Do not sum an observer's neighbor rows against a candidate while leaving all other APs at their current channels. That produces misleading results such as moving several APs to channel 11 simply because each AP was evaluated alone.
- Guardrails:
- Avoid changing all APs at once.
- Keep at least one stable channel anchor per area.
- With enough APs to use the practical 2.4 GHz set, keep every candidate channel represented unless measured RF data clearly justifies abandoning one.
- When topology and RF scores permit, prefer a balanced channel population. For
eight APs on three channels, prefer counts of
3/3/2(in deterministic channel order) over a4/3/1or more concentrated distribution. - Treat a mathematically lower score that moves many APs or abandons a channel as a candidate for staged review, not as an automatic rollout.
- Respect hardware/regulatory constraints reported by UniFi.
Example Scoring Heuristic
For each observed neighbor relation:
- Same channel penalty:
p_same = rssi_weight(signal) - Adjacent channel penalty (2.4 GHz):
p_adj = 0.5 * rssi_weight(signal) - Non-overlapping channel penalty:
0
Total candidate score:
score(ap, ch) = sum(penalties from all neighbors seen by ap on/near ch)
Lower score is better.
Output Contract
Return a plan table with:
ap_maccurrent_channelproposed_channelbandconfidence(high|medium|low)reason(top 1-3 conflict drivers)
Also return summary metrics:
- Estimated co-channel conflict delta
- Number of APs changed
- APs skipped with reason
Safe Rollout Workflow
- Discovery:
- Run
list_sitesand selectsite_id. - Build managed AP set (
type=uap). - Pull internal graph with
list_site_internal_ap_neighbors_v2over a fixed window (default 24h). - If needed, inspect problematic APs with
list_ap_neighbors_v2. - Optionally pull
list_neighboring_aps(site_id, min_rssi=-85)for external context.
- Plan:
- Generate per-AP candidate ranking and proposed channels.
- Mark risky APs (sparse data, stale
last_seen, extreme noise).
- Stage:
- Apply to small batch first with
set_ap_radio_channel. - Rollout defaults: first wave maximum 3 AP radios; subsequent waves maximum 25% of remaining changed radios; never change more than 50% of site radios without explicit confirmation.
- Persist the original channel, width, and power settings for every change.
- Wait validation window and compare client health/events.
- If AP instability or client disconnects exceed the configured threshold, restore the persisted settings before continuing.
- Expand:
- Roll out remaining APs in waves.
- Re-run neighbor scan and adjust.
Validation Checks
After each rollout wave, verify:
- AP online state is stable.
- Client disconnect spikes did not increase.
- Channel reuse distance improved in dense zones.
- No AP is assigned unsupported channel width/channel pair.
Pre-plan data-quality checks:
- Confirm each managed AP has at least one internal neighbor observation in the selected window, otherwise mark low-confidence.
- Treat
channel=autoas unknown current state. Infer it only when the v2 graph provides a fresh observation of that AP as a neighbour. Mark the inferred current state and resulting recommendation medium-confidence. If the AP is not observed as a neighbour, keep it unchanged and mark low-confidence. - Distinguish the observed neighbor's channel from the observer's channel:
the
channelfield on a v2 edge describes the observed neighbor/BSSID. - Read the observer's current channel from AP radio configuration or telemetry;
never infer it from a row where that AP is the observer. An AP configured as
Automay be inferred from a fresh row where its MAC is the observed neighbour, and may be changed to the proposed fixed channel when the plan is explicitly accepted. - Reject impossible RSSI outliers for planning (for example values above -20 dBm or below -95 dBm unless intentionally configured).
- If internal graph is empty, do not derive channel plan from
rogueapalone.
Confidence must be deterministic:
high: complete internal data, fresh observations, known capabilities, and a clear score improvement or a validated no-op.medium: partial or stale data, inferredAutostate, missing width, or a marginal score difference.low: no or very few observations, skipped APs, unknown capabilities, or an unknown current channel.
Failure Handling
- If neighbor dataset is empty for a site, do not auto-assign.
- If an AP has no observations, keep current channel and mark
lowconfidence. - If an AP is configured as
Autoand its current channel is inferred from a fresh neighbour observation, preserve the originalAutosetting for rollback and allow the accepted plan to set an explicit fixed channel. - On per-AP apply failure, continue with others and report partial status.
- If
list_site_internal_ap_neighbors_v2reportsskipped_aps, keep those APs unchanged and mark low confidence. - If only
rogueapis available and internal AP graph is missing, return "insufficient internal data" instead of proposing deterministic AP-to-AP assignments. - If the current configuration is already within the accepted score tolerance,
return a valid no-op plan with
0 APs changed; do not manufacture changes.
Example Prompt Pattern
"For site X, use the internal AP neighbor graph to produce a low-interference channel plan per AP for 2.4 GHz first. Use channels 1/6/11 only, use minimum RSSI -85, minimize same-channel conflicts, and return deterministic sorted results with reasons. Fetch external rogue-AP data only if needed for context."
In this repository52 other files it gives its agents.
- AGENTS.mdAGENTS.md
- .agents/skills/fastmcp/CLAUDE.mdCLAUDE.md
- CLAUDE.mdCLAUDE.md
- .claude/skills/fastmcp/CLAUDE.mdCLAUDE.md
- .cursor/rules/common-mistakes.mdcCursor rule
- .cursor/rules/core-principles.mdcCursor rule
- .cursor/rules/environment-setup.mdcCursor rule
- .cursor/rules/mcp-tools.mdcCursor rule
- .cursor/rules/project-context.mdcCursor rule
- .cursor/rules/README.mdCursor rule
- .cursor/rules/unifi-api.mdcCursor rule
- .cursor/rules/workflow.mdcCursor rule
- FastMCP DevelopmentSkill
- mcp-builderSkill
- source-command-build-dockerSkill
- source-command-check-depsSkill
- source-command-cleanSkill
- source-command-docsSkill
- source-command-formatSkill
- source-command-lintSkill
- source-command-prSkill
- source-command-securitySkill
- source-command-setupSkill
- source-command-testSkill
- source-command-unifi-api-docs-update-2Skill
- source-command-unifi-api-docs-updateSkill
- source-command-unifi-mcp-add-toolSkill
- source-command-unifi-mcp-release-prepSkill
- source-command-unifi-mcp-test-coverageSkill
- source-command-unifi-mcp-update-docsSkill
- unifi-cloud-fleet-toolsSkill
- unifi-mcp-tool-builderSkill
- unifi-network-config-toolsSkill
- unifi-protect-toolsSkill
- unifi-security-toolsSkill
- FastMCP DevelopmentSkill
- mcp-builderSkill
- unifi-cloud-fleet-toolsSkill
- unifi-mcp-tool-builderSkill
- unifi-network-config-toolsSkill
- unifi-protect-toolsSkill
- unifi-security-toolsSkill
- unifiSkill
- unifi-cloud-fleet-toolsSkill
- unifi-devicesSkill
- unifi-mcp-tool-builderSkill
- unifi-network-config-toolsSkill
- unifi-networkSkill
- unifi-protect-toolsSkill
- unifi-securitySkill
- unifi-security-toolsSkill
- unifi-systemSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

