Best-practice config linter
The linter checks your controller’s configuration against 30 best-practice rules and lists what it finds, worst first. It reads the daily config snapshot, not the controller, so a run is quick and makes no controller calls. Any role can run it. Five rules come with a fix that Claude can turn into a MOP for you to approve. The linter is MCP-only: you ask Claude.
What does the linter read?
Section titled “What does the linter read?”The last daily config snapshot: zones, WLANs, AP groups, four system
settings, and each ICX switch’s newest SwitchM backup. Its findings describe the
configuration as of the snapshot’s time (snapshotAt), which Claude should tell
you. For a fresh one, an engineer asks Claude to take a snapshot first
(history.snapshot_config()); see
Config snapshots and drift.
With no snapshot yet, the linter answers no_snapshot: “No config snapshot yet:
the daily refresh takes one after a good inventory sync, or an engineer can run
history.snapshot_config().”
The snapshot holds digests, not secrets. To spot a weak passphrase or SNMP community, the linter compares digests of a list of well-known weak values. A finding can name a weak SNMP community, but never a passphrase.
How do I run it?
Section titled “How do I run it?”Ask Claude, for example “lint the controller” or “what’s wrong with the
Guest WLAN’s config?” It calls lint.run:
| Argument | Default | What it does |
|---|---|---|
rules | All | Only these rule ids (lint.rules() lists them) |
kinds | All | zone, wlan, apgroup, system, switchconfig |
entity | — | One object and what is under it, such as a zone |
minSeverity | info (everything) | critical, warning or info |
includeWaived | Off | Waived findings are left out unless this is on |
limit | 200 (at most 1,000) | Findings returned |
Each finding has an id (<rule>@<object>), a severity (critical, warning
or info), the object, a detail and a suggested fix. A summary counts critical,
warning, info, waived and fixable findings.
Which findings can be fixed for me?
Section titled “Which findings can be fixed for me?”Five rules carry a fix: guest WLANs without client isolation (turn it on), hidden SSIDs (broadcast the SSID), 802.11b rates (turn on OFDM-only), overlapping 2.4 GHz channels (limit the channel range), and 40 MHz on 2.4 GHz (set 20 MHz). Each fix changes one field of a WLAN, zone or AP group that carries no secret.
The other 25 rules give advice only. That includes all seven ICX switch rules, and any rule whose fix would touch encryption settings, since those carry the passphrase.
lint.to_mop builds a MOP from fixable findings, picked by ids (from
lint.run) or by the same scope arguments:
- per finding, a pre-check that the object still reads as the snapshot saw it, so a fix is never built on stale configuration;
- the change (a
PATCHwith automatic rollback); - a post-check that the object reads back as fixed;
- a change window on the zones touched (
minutes, default 60, 1 to 1,440).
It returns the MOP without saving it. With save: true it is saved as a MOP,
which needs the engineer role. Running it is then a normal
MOP run that you approve: Claude suggests
onFail: 'rollback'.
lint.to_mop result | Meaning |
|---|---|
skipped entries | Findings with no automatic fix (“No automatic fix: …”), or past 50 (“Over 50 fixes in one MOP; make another.”) |
nothing_to_fix | ”None of these findings has an automatic fix.” |
not_found | ”No current finding id (waived, fixed since the snapshot, or out of scope).” |
How do I accept a finding?
Section titled “How do I accept a finding?”Waive it, with a reason. lint.waive({ rule, key, reason, days }) accepts a
rule on one object (key), or on everything when key is left out. days
makes the waiver expire (1 to 3,650). Waiving the same rule and key again
replaces the waiver. lint.unwaive removes one, and lint.waivers() lists them
with who waived each and when. Waiving and unwaiving need the engineer role.
| Refused | Message |
|---|---|
| Empty or blank reason | ”A waiver needs a reason (why this is right here).” Leaving reason out altogether is refused by the call’s argument check |
| Reason over 500 characters | Refused by the call’s argument check before the linter sees it: reason is limited to 500 characters |
days out of range | Refused by the call’s argument check: days is a whole number from 1 to 3650 |
| Unknown rule | ”No lint rule id; lint.rules() lists them.” |
| 2,000 waivers already | ”At most 2000 waivers; remove some first.” |
Who can do what?
Section titled “Who can do what?”| Action | Role |
|---|---|
lint.rules, lint.run, lint.waivers, lint.to_mop (without saving) | Any role |
lint.to_mop with save: true, lint.waive, lint.unwaive | Engineer and above |
A viewer or operator who tries gets write_blocked: “Your role in this
organisation (viewer) can run the linter but not (what); an engineer or admin
can.”