[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6GX58W7NVFERYSC7QMQ71XC":3,"skill-same:01M6GX58W7NVFERYSC7QMQ71XC":77},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":37,"linkOnly":38,"markdownContent":39,"markdownBody":40,"frontMatter":41,"refName":26,"commitSha":57,"skillDirectory":58,"forksCount":59,"repositoryHtmlUrl":60,"repositoryHomepageUrl":6,"ownerHtmlUrl":61,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":62,"install":63,"resources":76},"01M6GX58W7NVFERYSC7QMQ71XC","opnsense",null,"OPNsense gateway intelligence plugin for EmberAI. Provides interface and VLAN management, firewall rule analysis, static routing, VPN tunnel status and configuration, DNS (Unbound), DHCP (Kea), IDS\u002FIPS (Suricata), traffic shaping, live diagnostics, and firmware management via the OPNsense REST API.","bluminal\u002Femberai","bluminal","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F260166565?v=4","01M6GX3XC0W0S4DSMM3WVJC3QJ","01M6GX3XJJK9YDQEWW5M24ZRSJ",1,"MIT","https:\u002F\u002Fgithub.com\u002Fbluminal\u002Femberai\u002Fblob\u002Fmain\u002Fopnsense\u002Fskills\u002Fopnsense\u002FSKILL.md",[],[5,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36],"write","unbound","traffic","interface","io","tunnel","vpn","intelligence","main","status","shaping","api","analysis","ips","suricata","ids","firewall","firmware","dns","2026-11-10 10:12:30",false,"---\nname: opnsense\nversion: 0.2.2\ndescription: >\n  OPNsense gateway intelligence plugin for EmberAI. Provides interface and\n  VLAN management, firewall rule analysis, static routing, VPN tunnel status\n  and configuration, DNS (Unbound), DHCP (Kea), IDS\u002FIPS (Suricata), traffic\n  shaping, live diagnostics, and firmware management via the OPNsense REST API.\nauthor: Bluminal Labs\nlicense: MIT\nrepository: https:\u002F\u002Fgithub.com\u002Fbluminal\u002Femberai\u002Ftree\u002Fmain\u002Fopnsense\ndocs: https:\u002F\u002Fbluminal.github.io\u002Femberai\u002Fopnsense\u002F\n\n# Vendor Plugin Contract fields (netex v1.0.0)\nnetex_vendor: opnsense\nnetex_role:\n  - gateway\nnetex_skills:\n  - interfaces\n  - firewall\n  - routing\n  - vpn\n  - security\n  - services\n  - diagnostics\n  - firmware\nnetex_write_flag: OPNSENSE_WRITE_ENABLED\nnetex_contract_version: \"1.0.0\"\n---\n\n# opnsense -- OPNsense Gateway Intelligence Plugin\n\nYou are operating the opnsense plugin for EmberAI. This plugin provides\nread and (when explicitly enabled) write access to an OPNsense firewall\nand router via its local REST API.\n\n## Knowledge Base\nBefore making changes, check `opnsense\u002Fknowledge\u002FINDEX.md` for entries\nmatching your current task. Read any files whose triggers match, especially\nthose marked `severity: critical`. This knowledge captures hard-won\noperational lessons that prevent outages and save debugging time.\n\nThis plugin covers the GATEWAY layer: interfaces, VLAN interfaces, routing\ntable, firewall rules and aliases, NAT, VPN tunnels, DNS resolver (Unbound),\nDHCP server (Kea), IDS\u002FIPS (Suricata), traffic shaping, and system diagnostics.\nIt does NOT manage switching, wireless SSIDs, or client WiFi associations --\nthose belong to the unifi plugin (edge layer).\n\n## API Pattern\nAll endpoints follow: {OPNSENSE_HOST}\u002Fapi\u002F{module}\u002F{controller}\u002F{command}\nAuthentication: HTTP Basic Auth -- OPNSENSE_API_KEY as username,\n                                  OPNSENSE_API_SECRET as password.\nGET  = read operations (safe, always permitted)\nPOST = write and action operations (gated by OPNSENSE_WRITE_ENABLED)\n\n## The Reconfigure Pattern (CRITICAL)\nOPNsense separates saving a configuration change from applying it to the\nrunning system. A write (POST to add\u002Fmodify a rule, interface, alias, etc.)\nstores the change in the config file but does NOT activate it. A separate\nPOST to {module}\u002F{controller}\u002Freconfigure pushes the config to the live\nsystem. This is the point of no return for any configuration change.\n\nAlways model this explicitly in write workflows:\n  Step N:   POST \u002Fapi\u002F{module}\u002F{controller}\u002Fset_item  (saves config)\n  Step N+1: POST \u002Fapi\u002F{module}\u002F{controller}\u002Freconfigure  (applies to live)\n\nDry-run mode: show both steps in the plan but skip Step N+1 entirely.\nNever call reconfigure without explicit operator confirmation.\n\n## Authentication\n\nRequired environment variables:\n  OPNSENSE_HOST       : IP or hostname of the OPNsense instance\n                        (e.g., https:\u002F\u002F192.168.1.1 or https:\u002F\u002Ffw.local)\n  OPNSENSE_API_KEY    : API key (Basic Auth username). Created in\n                        OPNsense: System > Access > Users > Edit > API keys.\n  OPNSENSE_API_SECRET : API secret (Basic Auth password).\n\nOptional:\n  OPNSENSE_WRITE_ENABLED : \"true\" to enable write\u002FPOST operations.\n                           Default: false.\n  OPNSENSE_VERIFY_SSL    : \"false\" to skip TLS certificate verification\n                           for self-signed certs. Default: true.\n                           Warn the operator if set to false.\n\nPrivilege note: The API key owner must have Effective Privileges covering\nthe resources you intend to access. Insufficient privileges return 403.\nWhen a 403 is received, tell the operator which resource requires access\nand where to grant it (System > Access > Users > Effective Privileges).\n\n## Interaction Model\n\nSame three-phase plan-level confirmation model as the unifi plugin.\nAdditional OPNsense-specific rules:\n\n1. Always include the reconfigure step explicitly in any write plan.\n   Label it clearly: \"Step N: Apply config to live system (reconfigure).\"\n   This step is never implied -- the operator must see it and confirm.\n\n2. Before any firewall rule change, check the current rule list and show\n   where the new rule will be inserted in the rule order. Rule position\n   affects effective policy -- never add a rule without stating its position.\n\n3. Interface and VLAN changes carry the highest outage risk of any\n   OPNsense operation. If the operator's session traverses the interface\n   being modified, classify as CRITICAL risk and require out-of-band\n   confirmation before showing the plan.\n\n4. For Suricata (IDS\u002FIPS), any rule or policy change that triggers a\n   service restart may cause a brief interruption to IDS inspection.\n   State this explicitly in the plan.\n\nOPNSENSE_WRITE_ENABLED must be \"true\" AND the operator must have confirmed\nthe full plan before any POST call is made.\n\n## Skill Groups and Tool Signatures\n\n### interfaces skill\nopnsense__interfaces__list_interfaces()\n  -> [{name, description, ip, subnet, type, enabled, vlan_id?}]\n  API: GET \u002Fapi\u002Finterfaces\u002Foverview\u002Fexport\n\nopnsense__interfaces__list_vlan_interfaces()\n  -> [{uuid, tag, if, description, parent_if, pcp?}]\n  API: GET \u002Fapi\u002Finterfaces\u002Fvlan\u002FsearchItem\n\nopnsense__interfaces__configure_vlan(tag, parent_if, ip, subnet,\n                                     dhcp_range_from?, dhcp_range_to?,\n                                     description?)  # WRITE -- atomic\n  Combines: add VLAN interface + assign + static IP + DHCP scope in one\n  confirmed workflow with a single reconfigure at the end.\n  -> {vlan_uuid, interface_name, dhcp_uuid?}\n  Use this instead of add_vlan_interface for all new workflows.\n\nopnsense__interfaces__add_vlan_interface(tag, parent_if, description)  # WRITE\n  -> {uuid}  then reconfigure: POST \u002Fapi\u002Finterfaces\u002Fvlan\u002Freconfigure\n  Note: Retained for cases where only the VLAN definition is needed.\n\nopnsense__interfaces__add_dhcp_reservation(interface, mac, ip,\n                                            hostname?)  # WRITE\n  -> {uuid}  then reconfigure: POST \u002Fapi\u002Fkea\u002Fctrl_agent\u002Frestart\n  API: POST \u002Fapi\u002Fkea\u002Fdhcpv4\u002FaddReservation\n\nopnsense__interfaces__get_dhcp_leases(interface?)\n  -> [{mac, ip, hostname, expiry, state, interface}]\n  API: GET \u002Fapi\u002Fkea\u002Fleases4\u002Fsearch\n\nopnsense__interfaces__add_dhcp_subnet(interface, subnet, range_from,\n                                       range_to, dns_servers[])  # WRITE\n  -> {uuid}  then reconfigure: POST \u002Fapi\u002Fkea\u002Fctrl_agent\u002Frestart\n\n\n### firewall skill\nopnsense__firewall__list_rules(interface?)\n  -> [{uuid, description, action, enabled, direction, protocol,\n        source, destination, log, position}]\n  API: GET \u002Fapi\u002Ffirewall\u002Ffilter\u002FsearchRule\n\nopnsense__firewall__get_rule(uuid)\n  -> full rule object including all fields and metadata\n\nopnsense__firewall__list_aliases()\n  -> [{uuid, name, type, description, content}]\n  API: GET \u002Fapi\u002Ffirewall\u002Falias\u002FsearchItem\n\nopnsense__firewall__list_nat_rules()\n  -> [{uuid, description, interface, protocol, src, dst,\n        target, target_port, enabled}]\n  API: GET \u002Fapi\u002Ffirewall\u002Fs_nat\u002FsearchRule\n\nopnsense__firewall__add_rule(interface, action, src, dst, protocol,\n                              description, position?)  # WRITE\n  -> {uuid}  then reconfigure: POST \u002Fapi\u002Ffirewall\u002Ffilter\u002Fapply\n\nopnsense__firewall__toggle_rule(uuid, enabled)  # WRITE\n  -> {changed}  then reconfigure: POST \u002Fapi\u002Ffirewall\u002Ffilter\u002Fapply\n\nopnsense__firewall__add_alias(name, type, content[], description?)  # WRITE\n  type: host | network | port | url\n  content: list of values (CIDRs, IPs, port ranges, URLs)\n  -> {uuid}  then reconfigure: POST \u002Fapi\u002Ffirewall\u002Falias\u002Freconfigure\n  API: POST \u002Fapi\u002Ffirewall\u002Falias\u002FaddItem\n  Required before any rule that references a named alias.\n\n### routing skill\nopnsense__routing__list_routes()\n  -> [{uuid, network, gateway, description, disabled}]\n  API: GET \u002Fapi\u002Froutes\u002Froutes\u002FsearchRoute\n\nopnsense__routing__list_gateways()\n  -> [{name, interface, gateway, monitor, status, priority, rtt_ms?}]\n  API: GET \u002Fapi\u002Froutes\u002Fgateway\u002Fstatus\n\nopnsense__routing__add_route(network, gateway, description)  # WRITE\n  -> {uuid}  then reconfigure: POST \u002Fapi\u002Froutes\u002Froutes\u002Freconfigure\n\n\n### vpn skill\nopnsense__vpn__list_ipsec_sessions()\n  -> [{id, description, status, local_ts, remote_ts,\n        rx_bytes, tx_bytes, established_at?}]\n  API: GET \u002Fapi\u002Fipsec\u002Fsessions\u002Fsearch\n\nopnsense__vpn__list_openvpn_instances()\n  -> [{uuid, description, role, dev_type, protocol, port,\n        enabled, connected_clients?}]\n  API: GET \u002Fapi\u002Fopenvpn\u002Finstances\u002Fsearch\n\nopnsense__vpn__list_wireguard_peers()\n  -> [{uuid, name, public_key, endpoint?, allowed_ips[],\n        last_handshake?, rx_bytes?, tx_bytes?}]\n  API: GET \u002Fapi\u002Fwireguard\u002Fclient\u002Fsearch\n\nopnsense__vpn__get_vpn_status()\n  -> {ipsec: {up, down}, openvpn: {instances[]}, wireguard: {peers[]}}\n\n\n### security skill (IDS\u002FIPS -- Suricata)\nopnsense__security__get_ids_alerts(hours?=24, severity?=\"all\")\n  -> [{timestamp, signature, category, severity, src_ip,\n        dst_ip, proto, action}]\n  API: GET \u002Fapi\u002Fids\u002Fservice\u002FqueryAlerts\n\nopnsense__security__get_ids_rules(filter?)\n  -> [{sid, msg, category, enabled, action}]\n  API: GET \u002Fapi\u002Fids\u002Frule\u002FsearchRule\n\nopnsense__security__get_ids_policy()\n  -> {enabled, interfaces[], block_mode, alert_only_mode,\n       ruleset_count, last_update}\n  API: GET \u002Fapi\u002Fids\u002Fsettings\u002FgetSettings\n\nopnsense__security__get_certificates()\n  -> [{cn, san[], issuer, not_before, not_after, days_until_expiry,\n        in_use_for[]}]\n  API: GET \u002Fapi\u002Ftrust\u002Fcert\u002Fsearch\n\n\n### services skill\nopnsense__services__get_dns_overrides()\n  -> [{uuid, hostname, domain, ip, description, enabled}]\n  API: GET \u002Fapi\u002Funbound\u002Fsettings\u002FsearchHostOverride (26.x)\n  Graceful 404: returns [] if Unbound not installed\n\nopnsense__services__get_dns_forwarders()\n  -> [{uuid, server, port, domain?, dot_enabled}]\n  API: GET \u002Fapi\u002Funbound\u002Fsettings\u002FsearchDomainOverride (26.x)\n  Graceful 404: returns [] if Unbound not installed\n\nopnsense__services__resolve_hostname(hostname)\n  -> {hostname, ip, ttl, source}\n  API: GET \u002Fapi\u002Funbound\u002Fdiagnostics\u002Flookup\u002F{hostname}\n\nopnsense__services__add_dns_override(hostname, domain, ip,\n                                      description?)  # WRITE\n  -> {uuid}  then reconfigure: POST \u002Fapi\u002Funbound\u002Fservice\u002Freconfigure\n\nopnsense__services__get_dhcp_leases4(interface?)\n  -> [{mac, ip, hostname, expiry, state}]\n  API: GET \u002Fapi\u002Fkea\u002Fleases4\u002Fsearch\n\nopnsense__services__get_traffic_shaper()\n  -> {pipes: [{uuid, bandwidth, burst, delay, description}],\n       queues: [{uuid, pipe, weight, mask, description}]}\n  API: GET \u002Fapi\u002Ftrafficshaper\u002Fsettings\u002FgetSettings\n\n\n### diagnostics skill\nopnsense__diagnostics__run_ping(host, count?=5, source_ip?)\n  -> {host, output, completed, elapsed_seconds}\n  API: POST \u002Fapi\u002Fdiagnostics\u002Finterface\u002Fping + GET ...\u002FpingStatus\n  Note: 26.x async polling pattern. Starts ping, then polls for results.\n\nopnsense__diagnostics__run_traceroute(host, max_hops?=30)\n  -> {host, output, completed, elapsed_seconds}\n  API: POST \u002Fapi\u002Fdiagnostics\u002Finterface\u002Ftrace + GET ...\u002FtraceStatus\n  Note: 26.x async polling pattern. Starts traceroute, then polls for results.\n\nopnsense__diagnostics__run_host_discovery(interface)\n  -> [{ip, mac, hostname?, last_seen}]\n  API: POST \u002Fapi\u002Fdiagnostics\u002Finterface\u002FstartScan + GET ...\u002FgetScanResult\n  Note: Discovery scan runs asynchronously. Poll for results.\n\nopnsense__diagnostics__get_lldp_neighbors(interface?)\n  -> [{local_port, neighbor_system, neighbor_port, neighbor_ip?,\n        neighbor_capabilities, ttl}]\n  API: GET \u002Fapi\u002Fdiagnostics\u002Flldp\u002FgetNeighbors\n  Returns LLDP neighbor table -- what device is connected to each port.\n  Essential for physical topology verification and port assignment workflows.\n  Read-only.\n\nopnsense__diagnostics__dns_lookup(hostname, record_type?=\"A\")\n  -> [{name, type, value, ttl}]\n  API: GET \u002Fapi\u002Funbound\u002Fdiagnostics\u002Flookup\n\n\n### firmware skill\nopnsense__firmware__get_status()\n  -> {current_version, latest_version, upgrade_available,\n       last_check, changelog_url?}\n  API: GET \u002Fapi\u002Fcore\u002Ffirmware\u002Fstatus\n\nopnsense__firmware__list_packages()\n  -> [{name, version, latest_version, needs_update, description}]\n  API: GET \u002Fapi\u002Fcore\u002Ffirmware\u002Finfo\n\n## Commands\n\n### opnsense scan\nIntent: Full inventory of the OPNsense instance. Entry point for new deployments.\nCalls: interfaces.list_interfaces -> interfaces.list_vlan_interfaces\n       -> routing.list_routes -> routing.list_gateways\n       -> vpn.get_vpn_status -> firmware.get_status\nOutput: Interface summary, VLAN count, active routes, VPN tunnel count,\n  firmware status. Flag any interfaces that are down or gateways with loss.\n\n### opnsense health\nCalls: routing.list_gateways (latency\u002Floss) -> security.get_ids_alerts(hours=24)\n       -> firmware.get_status -> diagnostics.run_ping(8.8.8.8) [WAN reachability]\n       -> security.get_certificates [flag certs expiring within 30 days]\n\n### opnsense diagnose [interface?|host?]\nFor host: diagnostics.run_ping -> run_traceroute -> dns_lookup\n          -> firewall.list_rules (check traversal path)\nFor interface: interfaces.list_interfaces -> routing.list_gateways\n               -> run_host_discovery -> get_dhcp_leases4\n\n### opnsense firewall [--audit]\nBase: firewall.list_rules -> list_aliases -> list_nat_rules\n--audit adds: shadow analysis (compare rules in order for redundancy\u002Fconflict),\n  overly-broad rule detection (any\u002Fany src or dst), disabled rule count.\n\n### opnsense firewall policy-from-matrix --matrix \u003Cfile> [--audit] [--apply]\nAccepts an inter-VLAN access matrix (source, destination, allow|block).\n--audit: compare existing rules to the matrix; surface gaps and violations.\n--apply: derive the minimum correct ruleset -- creates needed aliases first,\n  adds rules in correct order, single reconfigure at the end.\nMatrix format: YAML or CSV. Source\u002Fdestination accept VLAN IDs, names, or\n  special values (inet, *, self).\nThe NSA reviews the derived ruleset before plan presentation.\n\n### opnsense vlan [--configure] [--audit]\nBase: interfaces.list_vlan_interfaces -> interfaces.list_interfaces\n--configure: Three-phase write flow using configure_vlan (atomic):\n  single step creates VLAN interface + static IP + DHCP scope.\n  Understands intentional range offsets within larger subnets (e.g.\n  Homelab \u002F21 with DHCP starting at .1.100 -- not a misconfiguration).\n--audit: Check each VLAN has a corresponding DHCP scope; flag orphans.\n\n### opnsense dhcp reserve-batch \u003Cinterface> --devices \u003Cspec> [--apply]\nCreate multiple static DHCP reservations in one confirmed workflow.\nDevice spec: inline or file, one entry per line: hostname:mac:ip\nSingle reconfigure at the end covers all reservations.\nCalls: get_dhcp_leases (verify MACs known) -> add_dhcp_reservation (xN)\n       -> reconfigure.\n\n### opnsense vpn [--tunnel \u003Cn>]\nCalls: vpn.list_ipsec_sessions -> list_openvpn_instances\n       -> list_wireguard_peers\nFilter to named tunnel if --tunnel is specified.\nFlag: sessions not established, handshakes older than 3 minutes (WireGuard),\n  near-expiry certificates used by VPN.\n\n### opnsense dns [hostname?]\nCalls: services.get_dns_overrides -> get_dns_forwarders\n       -> [resolve_hostname(hostname) if hostname specified]\nFlag: resolvers without DNS-over-TLS, open recursion enabled.\n\n### opnsense secure\nCalls: firewall.list_rules (shadow analysis) -> security.get_ids_policy\n       -> security.get_ids_alerts(hours=72) -> security.get_certificates\n       -> firewall.list_nat_rules (exposure review)\nFlag: IDS disabled, rulesets not updated in >7 days, certs expiring in \u003C60 days,\n  NAT rules exposing management ports.\n\n### opnsense firmware\nCalls: firmware.get_status -> firmware.list_packages\nFlag: available upgrades, packages with pending updates.\nWrite (--update): Three-phase confirmation. Never trigger reboot automatically.\n  Always state: \"This will restart the firewall. Confirm you have console access.\"\n\n## Examples\n\n# Basic: First-time scan of the OPNsense instance\nUser: \"Scan my OPNsense firewall\"\n-> call opnsense__interfaces__list_interfaces()\n-> call opnsense__interfaces__list_vlan_interfaces()\n-> call opnsense__routing__list_gateways()\n-> call opnsense__vpn__get_vpn_status()\n-> call opnsense__firmware__get_status()\n-> present: interface summary, VLAN count, gateway status, VPN tunnels, firmware\n\n# Basic: Health check\nUser: \"Quick health check on the firewall\"\n-> call opnsense__routing__list_gateways() (check latency\u002Floss)\n-> call opnsense__security__get_ids_alerts(hours=24)\n-> call opnsense__firmware__get_status()\n-> call opnsense__diagnostics__run_ping(\"8.8.8.8\")\n-> call opnsense__security__get_certificates()\n-> present: gateway health, IDS alerts, firmware status, WAN reachability, cert expiry\n\n# Advanced: Firewall audit\nUser: \"Audit my firewall rules\"\n-> call opnsense__firewall__list_rules()\n-> call opnsense__firewall__list_aliases()\n-> call opnsense__firewall__list_nat_rules()\n-> analyze: shadow rules, overly-broad rules, disabled rules, NAT exposure\n-> present: risk-ranked findings with remediation guidance\n\n# Write: Add a VLAN with DHCP (with OPNSENSE_WRITE_ENABLED=true)\nUser: \"Add VLAN 30 for IoT devices on igc3, subnet 10.30.0.0\u002F24 with DHCP\"\n-> Phase 1: check VLAN 30 is free, identify parent interface igc3\n-> Phase 2: present plan: add VLAN interface + static IP + DHCP scope + reconfigure\n-> Phase 3: AskUserQuestion \"4 steps planned. Confirm to proceed?\"\n-> on confirm: execute configure_vlan, report result\n","# opnsense -- OPNsense Gateway Intelligence Plugin\n\nYou are operating the opnsense plugin for EmberAI. This plugin provides\nread and (when explicitly enabled) write access to an OPNsense firewall\nand router via its local REST API.\n\n## Knowledge Base\nBefore making changes, check `opnsense\u002Fknowledge\u002FINDEX.md` for entries\nmatching your current task. Read any files whose triggers match, especially\nthose marked `severity: critical`. This knowledge captures hard-won\noperational lessons that prevent outages and save debugging time.\n\nThis plugin covers the GATEWAY layer: interfaces, VLAN interfaces, routing\ntable, firewall rules and aliases, NAT, VPN tunnels, DNS resolver (Unbound),\nDHCP server (Kea), IDS\u002FIPS (Suricata), traffic shaping, and system diagnostics.\nIt does NOT manage switching, wireless SSIDs, or client WiFi associations --\nthose belong to the unifi plugin (edge layer).\n\n## API Pattern\nAll endpoints follow: {OPNSENSE_HOST}\u002Fapi\u002F{module}\u002F{controller}\u002F{command}\nAuthentication: HTTP Basic Auth -- OPNSENSE_API_KEY as username,\n                                  OPNSENSE_API_SECRET as password.\nGET  = read operations (safe, always permitted)\nPOST = write and action operations (gated by OPNSENSE_WRITE_ENABLED)\n\n## The Reconfigure Pattern (CRITICAL)\nOPNsense separates saving a configuration change from applying it to the\nrunning system. A write (POST to add\u002Fmodify a rule, interface, alias, etc.)\nstores the change in the config file but does NOT activate it. A separate\nPOST to {module}\u002F{controller}\u002Freconfigure pushes the config to the live\nsystem. This is the point of no return for any configuration change.\n\nAlways model this explicitly in write workflows:\n  Step N:   POST \u002Fapi\u002F{module}\u002F{controller}\u002Fset_item  (saves config)\n  Step N+1: POST \u002Fapi\u002F{module}\u002F{controller}\u002Freconfigure  (applies to live)\n\nDry-run mode: show both steps in the plan but skip Step N+1 entirely.\nNever call reconfigure without explicit operator confirmation.\n\n## Authentication\n\nRequired environment variables:\n  OPNSENSE_HOST       : IP or hostname of the OPNsense instance\n                        (e.g., https:\u002F\u002F192.168.1.1 or https:\u002F\u002Ffw.local)\n  OPNSENSE_API_KEY    : API key (Basic Auth username). Created in\n                        OPNsense: System > Access > Users > Edit > API keys.\n  OPNSENSE_API_SECRET : API secret (Basic Auth password).\n\nOptional:\n  OPNSENSE_WRITE_ENABLED : \"true\" to enable write\u002FPOST operations.\n                           Default: false.\n  OPNSENSE_VERIFY_SSL    : \"false\" to skip TLS certificate verification\n                           for self-signed certs. Default: true.\n                           Warn the operator if set to false.\n\nPrivilege note: The API key owner must have Effective Privileges covering\nthe resources you intend to access. Insufficient privileges return 403.\nWhen a 403 is received, tell the operator which resource requires access\nand where to grant it (System > Access > Users > Effective Privileges).\n\n## Interaction Model\n\nSame three-phase plan-level confirmation model as the unifi plugin.\nAdditional OPNsense-specific rules:\n\n1. Always include the reconfigure step explicitly in any write plan.\n   Label it clearly: \"Step N: Apply config to live system (reconfigure).\"\n   This step is never implied -- the operator must see it and confirm.\n\n2. Before any firewall rule change, check the current rule list and show\n   where the new rule will be inserted in the rule order. Rule position\n   affects effective policy -- never add a rule without stating its position.\n\n3. Interface and VLAN changes carry the highest outage risk of any\n   OPNsense operation. If the operator's session traverses the interface\n   being modified, classify as CRITICAL risk and require out-of-band\n   confirmation before showing the plan.\n\n4. For Suricata (IDS\u002FIPS), any rule or policy change that triggers a\n   service restart may cause a brief interruption to IDS inspection.\n   State this explicitly in the plan.\n\nOPNSENSE_WRITE_ENABLED must be \"true\" AND the operator must have confirmed\nthe full plan before any POST call is made.\n\n## Skill Groups and Tool Signatures\n\n### interfaces skill\nopnsense__interfaces__list_interfaces()\n  -> [{name, description, ip, subnet, type, enabled, vlan_id?}]\n  API: GET \u002Fapi\u002Finterfaces\u002Foverview\u002Fexport\n\nopnsense__interfaces__list_vlan_interfaces()\n  -> [{uuid, tag, if, description, parent_if, pcp?}]\n  API: GET \u002Fapi\u002Finterfaces\u002Fvlan\u002FsearchItem\n\nopnsense__interfaces__configure_vlan(tag, parent_if, ip, subnet,\n                                     dhcp_range_from?, dhcp_range_to?,\n                                     description?)  # WRITE -- atomic\n  Combines: add VLAN interface + assign + static IP + DHCP scope in one\n  confirmed workflow with a single reconfigure at the end.\n  -> {vlan_uuid, interface_name, dhcp_uuid?}\n  Use this instead of add_vlan_interface for all new workflows.\n\nopnsense__interfaces__add_vlan_interface(tag, parent_if, description)  # WRITE\n  -> {uuid}  then reconfigure: POST \u002Fapi\u002Finterfaces\u002Fvlan\u002Freconfigure\n  Note: Retained for cases where only the VLAN definition is needed.\n\nopnsense__interfaces__add_dhcp_reservation(interface, mac, ip,\n                                            hostname?)  # WRITE\n  -> {uuid}  then reconfigure: POST \u002Fapi\u002Fkea\u002Fctrl_agent\u002Frestart\n  API: POST \u002Fapi\u002Fkea\u002Fdhcpv4\u002FaddReservation\n\nopnsense__interfaces__get_dhcp_leases(interface?)\n  -> [{mac, ip, hostname, expiry, state, interface}]\n  API: GET \u002Fapi\u002Fkea\u002Fleases4\u002Fsearch\n\nopnsense__interfaces__add_dhcp_subnet(interface, subnet, range_from,\n                                       range_to, dns_servers[])  # WRITE\n  -> {uuid}  then reconfigure: POST \u002Fapi\u002Fkea\u002Fctrl_agent\u002Frestart\n\n\n### firewall skill\nopnsense__firewall__list_rules(interface?)\n  -> [{uuid, description, action, enabled, direction, protocol,\n        source, destination, log, position}]\n  API: GET \u002Fapi\u002Ffirewall\u002Ffilter\u002FsearchRule\n\nopnsense__firewall__get_rule(uuid)\n  -> full rule object including all fields and metadata\n\nopnsense__firewall__list_aliases()\n  -> [{uuid, name, type, description, content}]\n  API: GET \u002Fapi\u002Ffirewall\u002Falias\u002FsearchItem\n\nopnsense__firewall__list_nat_rules()\n  -> [{uuid, description, interface, protocol, src, dst,\n        target, target_port, enabled}]\n  API: GET \u002Fapi\u002Ffirewall\u002Fs_nat\u002FsearchRule\n\nopnsense__firewall__add_rule(interface, action, src, dst, protocol,\n                              description, position?)  # WRITE\n  -> {uuid}  then reconfigure: POST \u002Fapi\u002Ffirewall\u002Ffilter\u002Fapply\n\nopnsense__firewall__toggle_rule(uuid, enabled)  # WRITE\n  -> {changed}  then reconfigure: POST \u002Fapi\u002Ffirewall\u002Ffilter\u002Fapply\n\nopnsense__firewall__add_alias(name, type, content[], description?)  # WRITE\n  type: host | network | port | url\n  content: list of values (CIDRs, IPs, port ranges, URLs)\n  -> {uuid}  then reconfigure: POST \u002Fapi\u002Ffirewall\u002Falias\u002Freconfigure\n  API: POST \u002Fapi\u002Ffirewall\u002Falias\u002FaddItem\n  Required before any rule that references a named alias.\n\n### routing skill\nopnsense__routing__list_routes()\n  -> [{uuid, network, gateway, description, disabled}]\n  API: GET \u002Fapi\u002Froutes\u002Froutes\u002FsearchRoute\n\nopnsense__routing__list_gateways()\n  -> [{name, interface, gateway, monitor, status, priority, rtt_ms?}]\n  API: GET \u002Fapi\u002Froutes\u002Fgateway\u002Fstatus\n\nopnsense__routing__add_route(network, gateway, description)  # WRITE\n  -> {uuid}  then reconfigure: POST \u002Fapi\u002Froutes\u002Froutes\u002Freconfigure\n\n\n### vpn skill\nopnsense__vpn__list_ipsec_sessions()\n  -> [{id, description, status, local_ts, remote_ts,\n        rx_bytes, tx_bytes, established_at?}]\n  API: GET \u002Fapi\u002Fipsec\u002Fsessions\u002Fsearch\n\nopnsense__vpn__list_openvpn_instances()\n  -> [{uuid, description, role, dev_type, protocol, port,\n        enabled, connected_clients?}]\n  API: GET \u002Fapi\u002Fopenvpn\u002Finstances\u002Fsearch\n\nopnsense__vpn__list_wireguard_peers()\n  -> [{uuid, name, public_key, endpoint?, allowed_ips[],\n        last_handshake?, rx_bytes?, tx_bytes?}]\n  API: GET \u002Fapi\u002Fwireguard\u002Fclient\u002Fsearch\n\nopnsense__vpn__get_vpn_status()\n  -> {ipsec: {up, down}, openvpn: {instances[]}, wireguard: {peers[]}}\n\n\n### security skill (IDS\u002FIPS -- Suricata)\nopnsense__security__get_ids_alerts(hours?=24, severity?=\"all\")\n  -> [{timestamp, signature, category, severity, src_ip,\n        dst_ip, proto, action}]\n  API: GET \u002Fapi\u002Fids\u002Fservice\u002FqueryAlerts\n\nopnsense__security__get_ids_rules(filter?)\n  -> [{sid, msg, category, enabled, action}]\n  API: GET \u002Fapi\u002Fids\u002Frule\u002FsearchRule\n\nopnsense__security__get_ids_policy()\n  -> {enabled, interfaces[], block_mode, alert_only_mode,\n       ruleset_count, last_update}\n  API: GET \u002Fapi\u002Fids\u002Fsettings\u002FgetSettings\n\nopnsense__security__get_certificates()\n  -> [{cn, san[], issuer, not_before, not_after, days_until_expiry,\n        in_use_for[]}]\n  API: GET \u002Fapi\u002Ftrust\u002Fcert\u002Fsearch\n\n\n### services skill\nopnsense__services__get_dns_overrides()\n  -> [{uuid, hostname, domain, ip, description, enabled}]\n  API: GET \u002Fapi\u002Funbound\u002Fsettings\u002FsearchHostOverride (26.x)\n  Graceful 404: returns [] if Unbound not installed\n\nopnsense__services__get_dns_forwarders()\n  -> [{uuid, server, port, domain?, dot_enabled}]\n  API: GET \u002Fapi\u002Funbound\u002Fsettings\u002FsearchDomainOverride (26.x)\n  Graceful 404: returns [] if Unbound not installed\n\nopnsense__services__resolve_hostname(hostname)\n  -> {hostname, ip, ttl, source}\n  API: GET \u002Fapi\u002Funbound\u002Fdiagnostics\u002Flookup\u002F{hostname}\n\nopnsense__services__add_dns_override(hostname, domain, ip,\n                                      description?)  # WRITE\n  -> {uuid}  then reconfigure: POST \u002Fapi\u002Funbound\u002Fservice\u002Freconfigure\n\nopnsense__services__get_dhcp_leases4(interface?)\n  -> [{mac, ip, hostname, expiry, state}]\n  API: GET \u002Fapi\u002Fkea\u002Fleases4\u002Fsearch\n\nopnsense__services__get_traffic_shaper()\n  -> {pipes: [{uuid, bandwidth, burst, delay, description}],\n       queues: [{uuid, pipe, weight, mask, description}]}\n  API: GET \u002Fapi\u002Ftrafficshaper\u002Fsettings\u002FgetSettings\n\n\n### diagnostics skill\nopnsense__diagnostics__run_ping(host, count?=5, source_ip?)\n  -> {host, output, completed, elapsed_seconds}\n  API: POST \u002Fapi\u002Fdiagnostics\u002Finterface\u002Fping + GET ...\u002FpingStatus\n  Note: 26.x async polling pattern. Starts ping, then polls for results.\n\nopnsense__diagnostics__run_traceroute(host, max_hops?=30)\n  -> {host, output, completed, elapsed_seconds}\n  API: POST \u002Fapi\u002Fdiagnostics\u002Finterface\u002Ftrace + GET ...\u002FtraceStatus\n  Note: 26.x async polling pattern. Starts traceroute, then polls for results.\n\nopnsense__diagnostics__run_host_discovery(interface)\n  -> [{ip, mac, hostname?, last_seen}]\n  API: POST \u002Fapi\u002Fdiagnostics\u002Finterface\u002FstartScan + GET ...\u002FgetScanResult\n  Note: Discovery scan runs asynchronously. Poll for results.\n\nopnsense__diagnostics__get_lldp_neighbors(interface?)\n  -> [{local_port, neighbor_system, neighbor_port, neighbor_ip?,\n        neighbor_capabilities, ttl}]\n  API: GET \u002Fapi\u002Fdiagnostics\u002Flldp\u002FgetNeighbors\n  Returns LLDP neighbor table -- what device is connected to each port.\n  Essential for physical topology verification and port assignment workflows.\n  Read-only.\n\nopnsense__diagnostics__dns_lookup(hostname, record_type?=\"A\")\n  -> [{name, type, value, ttl}]\n  API: GET \u002Fapi\u002Funbound\u002Fdiagnostics\u002Flookup\n\n\n### firmware skill\nopnsense__firmware__get_status()\n  -> {current_version, latest_version, upgrade_available,\n       last_check, changelog_url?}\n  API: GET \u002Fapi\u002Fcore\u002Ffirmware\u002Fstatus\n\nopnsense__firmware__list_packages()\n  -> [{name, version, latest_version, needs_update, description}]\n  API: GET \u002Fapi\u002Fcore\u002Ffirmware\u002Finfo\n\n## Commands\n\n### opnsense scan\nIntent: Full inventory of the OPNsense instance. Entry point for new deployments.\nCalls: interfaces.list_interfaces -> interfaces.list_vlan_interfaces\n       -> routing.list_routes -> routing.list_gateways\n       -> vpn.get_vpn_status -> firmware.get_status\nOutput: Interface summary, VLAN count, active routes, VPN tunnel count,\n  firmware status. Flag any interfaces that are down or gateways with loss.\n\n### opnsense health\nCalls: routing.list_gateways (latency\u002Floss) -> security.get_ids_alerts(hours=24)\n       -> firmware.get_status -> diagnostics.run_ping(8.8.8.8) [WAN reachability]\n       -> security.get_certificates [flag certs expiring within 30 days]\n\n### opnsense diagnose [interface?|host?]\nFor host: diagnostics.run_ping -> run_traceroute -> dns_lookup\n          -> firewall.list_rules (check traversal path)\nFor interface: interfaces.list_interfaces -> routing.list_gateways\n               -> run_host_discovery -> get_dhcp_leases4\n\n### opnsense firewall [--audit]\nBase: firewall.list_rules -> list_aliases -> list_nat_rules\n--audit adds: shadow analysis (compare rules in order for redundancy\u002Fconflict),\n  overly-broad rule detection (any\u002Fany src or dst), disabled rule count.\n\n### opnsense firewall policy-from-matrix --matrix \u003Cfile> [--audit] [--apply]\nAccepts an inter-VLAN access matrix (source, destination, allow|block).\n--audit: compare existing rules to the matrix; surface gaps and violations.\n--apply: derive the minimum correct ruleset -- creates needed aliases first,\n  adds rules in correct order, single reconfigure at the end.\nMatrix format: YAML or CSV. Source\u002Fdestination accept VLAN IDs, names, or\n  special values (inet, *, self).\nThe NSA reviews the derived ruleset before plan presentation.\n\n### opnsense vlan [--configure] [--audit]\nBase: interfaces.list_vlan_interfaces -> interfaces.list_interfaces\n--configure: Three-phase write flow using configure_vlan (atomic):\n  single step creates VLAN interface + static IP + DHCP scope.\n  Understands intentional range offsets within larger subnets (e.g.\n  Homelab \u002F21 with DHCP starting at .1.100 -- not a misconfiguration).\n--audit: Check each VLAN has a corresponding DHCP scope; flag orphans.\n\n### opnsense dhcp reserve-batch \u003Cinterface> --devices \u003Cspec> [--apply]\nCreate multiple static DHCP reservations in one confirmed workflow.\nDevice spec: inline or file, one entry per line: hostname:mac:ip\nSingle reconfigure at the end covers all reservations.\nCalls: get_dhcp_leases (verify MACs known) -> add_dhcp_reservation (xN)\n       -> reconfigure.\n\n### opnsense vpn [--tunnel \u003Cn>]\nCalls: vpn.list_ipsec_sessions -> list_openvpn_instances\n       -> list_wireguard_peers\nFilter to named tunnel if --tunnel is specified.\nFlag: sessions not established, handshakes older than 3 minutes (WireGuard),\n  near-expiry certificates used by VPN.\n\n### opnsense dns [hostname?]\nCalls: services.get_dns_overrides -> get_dns_forwarders\n       -> [resolve_hostname(hostname) if hostname specified]\nFlag: resolvers without DNS-over-TLS, open recursion enabled.\n\n### opnsense secure\nCalls: firewall.list_rules (shadow analysis) -> security.get_ids_policy\n       -> security.get_ids_alerts(hours=72) -> security.get_certificates\n       -> firewall.list_nat_rules (exposure review)\nFlag: IDS disabled, rulesets not updated in >7 days, certs expiring in \u003C60 days,\n  NAT rules exposing management ports.\n\n### opnsense firmware\nCalls: firmware.get_status -> firmware.list_packages\nFlag: available upgrades, packages with pending updates.\nWrite (--update): Three-phase confirmation. Never trigger reboot automatically.\n  Always state: \"This will restart the firewall. Confirm you have console access.\"\n\n## Examples\n\n# Basic: First-time scan of the OPNsense instance\nUser: \"Scan my OPNsense firewall\"\n-> call opnsense__interfaces__list_interfaces()\n-> call opnsense__interfaces__list_vlan_interfaces()\n-> call opnsense__routing__list_gateways()\n-> call opnsense__vpn__get_vpn_status()\n-> call opnsense__firmware__get_status()\n-> present: interface summary, VLAN count, gateway status, VPN tunnels, firmware\n\n# Basic: Health check\nUser: \"Quick health check on the firewall\"\n-> call opnsense__routing__list_gateways() (check latency\u002Floss)\n-> call opnsense__security__get_ids_alerts(hours=24)\n-> call opnsense__firmware__get_status()\n-> call opnsense__diagnostics__run_ping(\"8.8.8.8\")\n-> call opnsense__security__get_certificates()\n-> present: gateway health, IDS alerts, firmware status, WAN reachability, cert expiry\n\n# Advanced: Firewall audit\nUser: \"Audit my firewall rules\"\n-> call opnsense__firewall__list_rules()\n-> call opnsense__firewall__list_aliases()\n-> call opnsense__firewall__list_nat_rules()\n-> analyze: shadow rules, overly-broad rules, disabled rules, NAT exposure\n-> present: risk-ranked findings with remediation guidance\n\n# Write: Add a VLAN with DHCP (with OPNSENSE_WRITE_ENABLED=true)\nUser: \"Add VLAN 30 for IoT devices on igc3, subnet 10.30.0.0\u002F24 with DHCP\"\n-> Phase 1: check VLAN 30 is free, identify parent interface igc3\n-> Phase 2: present plan: add VLAN interface + static IP + DHCP scope + reconfigure\n-> Phase 3: AskUserQuestion \"4 steps planned. Confirm to proceed?\"\n-> on confirm: execute configure_vlan, report result\n",{"docs":42,"name":5,"author":43,"license":14,"version":44,"netex_role":45,"repository":47,"description":48,"netex_skills":49,"netex_vendor":5,"netex_write_flag":55,"netex_contract_version":56},"https:\u002F\u002Fbluminal.github.io\u002Femberai\u002Fopnsense\u002F","Bluminal Labs","0.2.2",[46],"gateway","https:\u002F\u002Fgithub.com\u002Fbluminal\u002Femberai\u002Ftree\u002Fmain\u002Fopnsense","OPNsense gateway intelligence plugin for EmberAI. Provides interface and VLAN management, firewall rule analysis, static routing, VPN tunnel status and configuration, DNS (Unbound), DHCP (Kea), IDS\u002FIPS (Suricata), traffic shaping, live diagnostics, and firmware management via the OPNsense REST API.\n",[50,34,51,24,52,53,54,35],"interfaces","routing","security","services","diagnostics","OPNSENSE_WRITE_ENABLED","1.0.0","9d6b1619ec04c0b28e3666ff6bc16f303fd1a340","opnsense\u002Fskills\u002Fopnsense",0,"https:\u002F\u002Fgithub.com\u002Fbluminal\u002Femberai","https:\u002F\u002Fgithub.com\u002Fbluminal","2026-08-18 23:17:24",{"source":8,"skillName":5,"commands":64,"prompt":74,"zipAvailable":75},[65,68,71],{"tool":66,"command":67},"npx","npx skills add bluminal\u002Femberai --skill opnsense",{"tool":69,"command":70},"bunx","bunx skills add bluminal\u002Femberai --skill opnsense",{"tool":72,"command":73},"pnpm","pnpm dlx skills add bluminal\u002Femberai --skill opnsense","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fbluminal\u002Femberai\u002Fblob\u002Fmain\u002Fopnsense\u002Fskills\u002Fopnsense\u002FSKILL.md",true,[],[78,96,121,146,165],{"skillNo":79,"name":80,"nameZh":6,"description":81,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":82,"categories":83,"keywords":84,"publishedAt":37},"01M6GX63EVRSAWS2ARXMMJEJDF","unifi","UniFi network intelligence plugin for EmberAI. Provides topology discovery, health monitoring, WiFi analysis, client management, traffic inspection, security audit, configuration drift detection, and multi-site operations across UniFi Site Manager, Cloud V1, and Local Gateway APIs.","https:\u002F\u002Fgithub.com\u002Fbluminal\u002Femberai\u002Fblob\u002Fmain\u002Funifi\u002Fskills\u002Funifi\u002FSKILL.md",[],[80,85,86,20,22,87,88,89,25,26,18,90,91,30,92,93,94,46,95,52],"network","manager","local","across","drift","wifi","security audit","monitoring","topology","audit","config",{"skillNo":97,"name":98,"nameZh":6,"description":99,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":100,"categories":101,"keywords":110,"publishedAt":37},"01M6GX5EF9HEN4QGDKNXEZE81E","talos","Talos Linux Kubernetes cluster intelligence plugin for EmberAI. Provides cluster lifecycle management, node health monitoring, etcd cluster operations, Kubernetes component status, diagnostics, configuration management, security auditing, and image management via talosctl CLI with gRPC + mTLS transport.","https:\u002F\u002Fgithub.com\u002Fbluminal\u002Femberai\u002Fblob\u002Fmain\u002Ftalos\u002FSKILL.md",[102,107],{"categoryNo":103,"categoryName":104,"taxonomyType":105,"taxonomyTypeDesc":106},"01JBSEEDCAT000000000000011","运维与部署","SCENARIO","使用场景",{"categoryNo":108,"categoryName":109,"taxonomyType":105,"taxonomyTypeDesc":106},"01JBSEEDCAT000000000000016","图像与多媒体",[98,52,18,111,112,113,92,114,54,27,95,115,26,116,117,118,119,120,22,25],"node","etcd","mtls","grpc","component","cli","image","images","tree","cluster",{"skillNo":122,"name":123,"nameZh":6,"description":124,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":125,"categories":126,"keywords":135,"publishedAt":37},"01M6GX4S1TT2FKWB50M933TGVG","nextdns","NextDNS intelligence plugin for EmberAI. Provides DNS profile management, security posture auditing, analytics dashboards, query log analysis, and parental control configuration across NextDNS profiles.","https:\u002F\u002Fgithub.com\u002Fbluminal\u002Femberai\u002Fblob\u002Fmain\u002Fnextdns\u002FSKILL.md",[127,130],{"categoryNo":128,"categoryName":129,"taxonomyType":105,"taxonomyTypeDesc":106},"01JBSEEDCAT000000000000013","分析与可视化",{"categoryNo":131,"categoryName":132,"taxonomyType":133,"taxonomyTypeDesc":134},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",[123,119,136,22,137,88,25,138,26,139,18,140,30,36,141,142,143,52,144,145],"profiles","control","query","log analysis","dashboards","logs","plugin","analytics","github","log",{"skillNo":147,"name":148,"nameZh":6,"description":149,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":150,"categories":151,"keywords":152,"publishedAt":37},"01M6GX4K560XNG4G64NNZDB7GC","netex","Cross-vendor network orchestration umbrella for EmberAI. Coordinates installed vendor plugins (unifi, opnsense, and future vendors) to perform operations that span multiple network systems. Provides unified topology, health, VLAN provisioning, cross-vendor security audits, and policy synchronization. Requires at least one conforming vendor plugin.","https:\u002F\u002Fgithub.com\u002Fbluminal\u002Femberai\u002Fblob\u002Fmain\u002Fnetex\u002Fskills\u002Fnetex\u002FSKILL.md",[],[148,153,142,154,155,144,156,119,157,22,158,159,26,80,160,161,162,163,164,85],"https","orchestration","policy","plugins","at","systems","coordinates","vendor","operations","synchronization","health","vlan",{"skillNo":166,"name":167,"nameZh":6,"description":168,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":169,"categories":170,"keywords":171,"publishedAt":37},"01M6GX47T042G7AGSVVCNMMGNC","cisco","Cisco SG-300 managed switch intelligence plugin for EmberAI. Provides VLAN management, port configuration, MAC address table lookup, LLDP topology discovery, interface counters (SNMP), configuration drift detection, and health monitoring via SSH CLI (Netmiko) and SNMPv2c.","https:\u002F\u002Fgithub.com\u002Fbluminal\u002Femberai\u002Fblob\u002Fmain\u002Fcisco\u002Fskills\u002Fcisco\u002FSKILL.md",[],[167,26,119,21,172,22,89,25,173,174,18,175,163,176,177,92,93,142,95,116],"port","switch","mac","table","discovery","edge"]