{"id":"aa0c79de-e4ca-4145-9588-f31bb24d22eb","entityType":"agent","slug":"clawhub-zw008-firewall-aiops","name":"firewall-aiops","canonicalUrl":"https://www.xpersona.co/agent/clawhub-zw008-firewall-aiops","canonicalPath":"/agent/clawhub-zw008-firewall-aiops","generatedAt":"2026-10-09T22:50:59.529Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T16:47:12.210Z","emptyReason":null},"description":"Use this skill whenever the user needs to operate an OPNsense or pfSense firewall — a one-shot overview, firmware/health, interfaces and gateways, firewall rules with hit-counts and shadow analysis, NAT (port-forward/outbound/1:1), aliases and their entries, VPN (WireGuard/OpenVPN/IPsec), DHCP leases and static mappings, the firewall log and state table, three flagship RCAs (gateway health, rule hit/shadow, blocked traffic), and governed writes (toggle a rule, add/remove an alias entry, kill states, restart a service, apply/reconfigure to make edits live, reboot). Always use this skill for \"OPNsense\", \"pfSense\", \"firewall rule\", \"port forward\", \"NAT\", \"alias\", \"WireGuard\", \"OpenVPN\", \"IPsec\", \"DHCP lease\", \"firewall log\", \"blocked traffic\", \"why is my WAN down\", \"gateway loss/latency\", \"unused / shadowed rules\", \"apply firewall changes\", \"reboot the firewall\" when the context is an OPNsense/pfSense firewall. Do NOT use when the target is something other than an OPNsense/pfSense firewall (a hypervisor, storage appliance, backup product, container-orchestration cluster, multi-vendor router/switch config, or OT/industrial equipment) — route those to the appropriate other AIops-tools skill. Cloud security groups and vendor firewall appliances are out of scope. Governed firewall operations with a built-in governance harness (audit, policy, token budget, undo, risk-tiers). Live-verified against real OPNsense 26.7 and pfSense CE 2.7.2 on top of the mock test suite; see docs/VERIFICATION.md for exactly what each run proved and what is still untested.","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 2.3K downloads reported by the source. Last updated 10/9/2026.","installCommand":"clawhub skill install s171xgnmqse0nqvgqvqnaq5f9183kyre:firewall-aiops","sourceUrl":"https://clawhub.ai/zw008/firewall-aiops","homepage":"https://clawhub.ai/zw008/skills/firewall-aiops","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/zw008/firewall-aiops","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/zw008/skills/firewall-aiops","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":67,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"firewall-aiops technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-09T16:47:12.210Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T16:47:12.210Z","emptyReason":null},"stars":null,"forks":null,"downloads":2276,"packageName":null,"latestVersion":"0.12.5","tractionLabel":"2.3K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T16:47:12.185Z","emptyReason":null},"lastUpdatedAt":"2026-10-09T16:47:12.210Z","lastCrawledAt":"2026-10-09T16:47:12.185Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-10T16:47:12.185Z","lastVerifiedAt":null,"highlights":[{"version":"0.12.5","createdAt":"2026-09-16T23:25:35.182Z","changelog":"- Documentation updates in SKILL.md and references/agent-guardrails.md for improved clarity and completeness. - Obsolete skill-card.md file removed. - No functional or compatibility changes in this release.","fileCount":7,"zipByteSize":20907},{"version":"0.12.4","createdAt":"2026-09-15T05:58:07.759Z","changelog":"- Removed the sample skill-card.md file. - No changes to core functionality or documentation content. - This update is a minor internal cleanup with no impact for end users.","fileCount":7,"zipByteSize":20005},{"version":"0.12.3","createdAt":"2026-09-12T23:40:16.038Z","changelog":"- Updated documentation: revised the setup guide (references/setup-guide.md). - Removed obsolete or unnecessary file: skill-card.md deleted. - No functional/tooling changes—this is a docs-focused update.","fileCount":7,"zipByteSize":19984},{"version":"0.12.2","createdAt":"2026-09-12T14:13:08.008Z","changelog":"- Removed redundant skill-card.md file for simpler maintenance. - Updated SKILL.md: clarified OpenClaw installation instructions by changing the plugin install command to reference @zw008/firewall-aiops instead of @aiops-tools/firewall-aiops. - No functional or toolset changes; documentation only.","fileCount":7,"zipByteSize":19955},{"version":"0.12.1","createdAt":"2026-09-12T10:05:41.296Z","changelog":"- Removed the redundant skill-card.md file. - SKILL.md updated with minor enhancements and clarified install instructions, including OpenClaw plugin installation and requirement for uvx on PATH. - No changes to features or tool count; overall functionality remains the same.","fileCount":7,"zipByteSize":19957},{"version":"0.12.0","createdAt":"2026-09-12T00:54:20.742Z","changelog":"- Removed the skill-card.md file. - Updated SKILL.md metadata to require either firewall-aiops or uvx binaries, instead of only firewall-aiops. - Expanded the list of optional environment variables in the SKILL.md metadata. - No changes to features or user-facing tools.","fileCount":7,"zipByteSize":20006},{"version":"0.11.0","createdAt":"2026-09-02T14:18:48.380Z","changelog":"- Removed the skill-card.md file. - No changes to functionality or user experience. - Maintenance release to clean up documentation files.","fileCount":7,"zipByteSize":19814},{"version":"0.10.0","createdAt":"2026-08-29T07:37:16.246Z","changelog":"- Adds real-world live-verification details: skill now explicitly documents testing against OPNsense 26.7 and pfSense CE 2.7.2, on top of the mock suite. - Updated skill description and compatibility notes to mention live evidence, with references to docs/VERIFICATION.md for specific test coverage status. - Removed outdated file: skill-card.md. - Minor clarifications and wording improvements in skill documentation regarding testing and verification.","fileCount":7,"zipByteSize":19816}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s171xgnmqse0nqvgqvqnaq5f9183kyre:firewall-aiops","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s171xgnmqse0nqvgqvqnaq5f9183kyre:firewall-aiops` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/zw008/firewall-aiops before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-firewall-aiops/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-firewall-aiops/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-firewall-aiops/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-zw008-firewall-aiops/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-zw008-firewall-aiops/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-zw008-firewall-aiops/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-09T22:50:59.525Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-firewall-aiops/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-firewall-aiops/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-firewall-aiops/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-firewall-aiops/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T16:47:12.210Z","emptyReason":null},"readme":"Skill: firewall-aiops\n\nOwner: zw008\n\nSummary: Use this skill whenever the user needs to operate an OPNsense or pfSense firewall — a one-shot overview, firmware/health, interfaces and gateways, firewall rules with hit-counts and shadow analysis, NAT (port-forward/outbound/1:1), aliases and their entries, VPN (WireGuard/OpenVPN/IPsec), DHCP leases and static mappings, the firewall log and state table, three flagship RCAs (gateway health, rule hit/shadow, blocked traffic), and governed writes (toggle a rule, add/remove an alias entry, kill states, restart a service, apply/reconfigure to make edits live, reboot). Always use this skill for \"OPNsense\", \"pfSense\", \"firewall rule\", \"port forward\", \"NAT\", \"alias\", \"WireGuard\", \"OpenVPN\", \"IPsec\", \"DHCP lease\", \"firewall log\", \"blocked traffic\", \"why is my WAN down\", \"gateway loss/latency\", \"unused / shadowed rules\", \"apply firewall changes\", \"reboot the firewall\" when the context is an OPNsense/pfSense firewall. Do NOT use when the target is something other than an OPNsense/pfSense firewall (a hypervisor, storage appliance, backup product, container-orchestration cluster, multi-vendor router/switch config, or OT/industrial equipment) — route those to the appropriate other AIops-tools skill. Cloud security groups and vendor firewall appliances are out of scope. Governed firewall operations with a built-in governance harness (audit, policy, token budget, undo, risk-tiers). Live-verified against real OPNsense 26.7 and pfSense CE 2.7.2 on top of the mock test suite; see docs/VERIFICATION.md for exactly what each run proved and what is still untested.\n\nTags: latest:0.12.5\n\nVersion history:\n\nv0.12.5 | 2026-09-16T23:25:35.182Z | auto\n\n- Documentation updates in SKILL.md and references/agent-guardrails.md for improved clarity and completeness.\n- Obsolete skill-card.md file removed.\n- No functional or compatibility changes in this release.\n\nv0.12.4 | 2026-09-15T05:58:07.759Z | auto\n\n- Removed the sample skill-card.md file.\n- No changes to core functionality or documentation content.\n- This update is a minor internal cleanup with no impact for end users.\n\nv0.12.3 | 2026-09-12T23:40:16.038Z | auto\n\n- Updated documentation: revised the setup guide (references/setup-guide.md).\n- Removed obsolete or unnecessary file: skill-card.md deleted.\n- No functional/tooling changes—this is a docs-focused update.\n\nv0.12.2 | 2026-09-12T14:13:08.008Z | auto\n\n- Removed redundant skill-card.md file for simpler maintenance.\n- Updated SKILL.md: clarified OpenClaw installation instructions by changing the plugin install command to reference @zw008/firewall-aiops instead of @aiops-tools/firewall-aiops.\n- No functional or toolset changes; documentation only.\n\nv0.12.1 | 2026-09-12T10:05:41.296Z | auto\n\n- Removed the redundant skill-card.md file.\n- SKILL.md updated with minor enhancements and clarified install instructions, including OpenClaw plugin installation and requirement for uvx on PATH.\n- No changes to features or tool count; overall functionality remains the same.\n\nv0.12.0 | 2026-09-12T00:54:20.742Z | auto\n\n- Removed the skill-card.md file.\n- Updated SKILL.md metadata to require either firewall-aiops or uvx binaries, instead of only firewall-aiops.\n- Expanded the list of optional environment variables in the SKILL.md metadata.\n- No changes to features or user-facing tools.\n\nv0.11.0 | 2026-09-02T14:18:48.380Z | auto\n\n- Removed the skill-card.md file.\n- No changes to functionality or user experience.\n- Maintenance release to clean up documentation files.\n\nv0.10.0 | 2026-08-29T07:37:16.246Z | auto\n\n- Adds real-world live-verification details: skill now explicitly documents testing against OPNsense 26.7 and pfSense CE 2.7.2, on top of the mock suite.\n- Updated skill description and compatibility notes to mention live evidence, with references to docs/VERIFICATION.md for specific test coverage status.\n- Removed outdated file: skill-card.md.\n- Minor clarifications and wording improvements in skill documentation regarding testing and verification.\n\nv0.9.0 | 2026-08-10T06:50:52.531Z | auto\n\n- Removed the file: skill-card.md\n- No functional changes to the skill's features or code—documentation file cleanup only.\n\nv0.8.0 | 2026-08-03T05:52:43.223Z | auto\n\n# firewall-aiops v0.8.0\n\n- Removed the file: skill-card.md\n- No other changes to functionality or documentation.\n\nv0.7.0 | 2026-08-02T09:39:08.720Z | auto\n\n- Removed the skill-card.md file.\n- No functional/tooling changes to skill logic or compatibility; metadata/docs only.\n\nv0.6.0 | 2026-07-21T09:40:58.724Z | auto\n\n- Governance harness now applies descriptive risk-tier labeling instead of gating; high-risk operations feature dry_run but do not require explicit approval.\n- Documentation and capability references updated to reflect changes in governance behaviour.\n- Removed obsolete skill-card.md file.\n- General documentation cleanup and clarifications.\n- No new tools or functional API changes.\n\nv0.5.0 | 2026-07-20T11:15:10.942Z | auto\n\n- Adds a new read-only tool: pending_changes, increasing the tool count to 35.\n- Documents additional safety checks: write operations (restart_service, apply_changes, reconfigure) now refuse actions that would cut off management access.\n- Updates documentation and capabilities in SKILL.md, setup, and guardrails guides.\n- Removes the legacy skill-card.md file.\n\nv0.4.0 | 2026-07-19T03:51:15.812Z | auto\n\n## firewall-aiops 0.4.0\n\n- Added agent guardrails documentation (references/agent-guardrails.md).\n- Introduced undo support with new tools: undo_list and undo_apply (bringing total tools to 34).\n- Updated documentation for new governance and undo features.\n- Improved agent and governance documentation; enhanced clarity of compatibility and usage.\n- Removed deprecated skill-card.md file.\n\nv0.3.0 | 2026-07-17T05:56:50.914Z | auto\n\n- Removed the file skill-card.md.\n- No user-facing features or behavior changed; this is a cleanup of documentation files only.\n\nv0.2.0 | 2026-07-13T13:10:23.354Z | auto\n\n## firewall-aiops 0.2.0 changelog\n\n- Documentation updated in SKILL.md for clarity and detail.\n- Removed obsolete skill-card.md file.\n- No functional or tool changes; update is documentation-only.\n\nv0.1.0 | 2026-07-13T06:24:50.914Z | auto\n\nfirewall-aiops v0.1.0 — Initial Preview Release\n\n- Introduces governed firewall operations for OPNsense and pfSense via unified REST API tools.\n- Offers 32 tools covering system status, firewall/NAT rules, aliases, VPN, DHCP, diagnostics, and three flagship root-cause analyses.\n- All state-changing actions are governed (policy engine, audit log, risk/undo framework).\n- Credentials are stored securely (AES-128 encrypted, not plaintext); all operations audited locally.\n- Preview/mock-only: commands are validated but not run against a live firewall.\n\nArchive index:\n\nArchive v0.12.5: 7 files, 20907 bytes\n\nFiles: references/agent-guardrails.md (8727b), references/capabilities.md (10693b), references/cli-reference.md (2530b), references/setup-guide.md (3664b), skill-card.md (2890b), SKILL.md (16254b), _meta.json (134b)\n\nFile v0.12.5:SKILL.md\n\n---\nname: firewall-aiops\nslug: firewall-aiops\ndisplayName: \"Firewall AIops\"\nsummary: \"Governed OPNsense + pfSense firewall ops: rules, NAT, VPN, DHCP, RCA. 35 tools.\"\nlicense: MIT\nhomepage: https://github.com/AIops-tools/Firewall-AIops\ntags: [aiops, mcp, governance, firewall]\ndescription: >\n  Use this skill whenever the user needs to operate an OPNsense or pfSense firewall — a one-shot overview, firmware/health, interfaces and gateways, firewall rules with hit-counts and shadow analysis, NAT (port-forward/outbound/1:1), aliases and their entries, VPN (WireGuard/OpenVPN/IPsec), DHCP leases and static mappings, the firewall log and state table, three flagship RCAs (gateway health, rule hit/shadow, blocked traffic), and governed writes (toggle a rule, add/remove an alias entry, kill states, restart a service, apply/reconfigure to make edits live, reboot).\n  Always use this skill for \"OPNsense\", \"pfSense\", \"firewall rule\", \"port forward\", \"NAT\", \"alias\", \"WireGuard\", \"OpenVPN\", \"IPsec\", \"DHCP lease\", \"firewall log\", \"blocked traffic\", \"why is my WAN down\", \"gateway loss/latency\", \"unused / shadowed rules\", \"apply firewall changes\", \"reboot the firewall\" when the context is an OPNsense/pfSense firewall.\n  Do NOT use when the target is something other than an OPNsense/pfSense firewall (a hypervisor, storage appliance, backup product, container-orchestration cluster, multi-vendor router/switch config, or OT/industrial equipment) — route those to the appropriate other AIops-tools skill. Cloud security groups and vendor firewall appliances are out of scope.\n  Governed firewall operations with a built-in governance harness (audit, policy, token budget, undo, risk-tiers). Live-verified against real OPNsense 26.7 and pfSense CE 2.7.2 on top of the mock test suite; see docs/VERIFICATION.md for exactly what each run proved and what is still untested.\ninstaller:\n  kind: uv\n  package: firewall-aiops\nargument-hint: \"[a rule/alias id, an IP, or describe your firewall task]\"\nallowed-tools:\n  - Bash\nmetadata: {\"openclaw\":{\"requires\":{\"anyBins\":[\"firewall-aiops\",\"uvx\"]},\"optional\":{\"env\":[\"FIREWALL_AIOPS_CONFIG\",\"FIREWALL_AIOPS_MASTER_PASSWORD\"]},\"homepage\":\"https://github.com/AIops-tools/Firewall-AIops\",\"emoji\":\"🛡️\",\"os\":[\"macos\",\"linux\"]}}\ncompatibility: >\n  Standalone, self-governed firewall operations across OPNsense (REST API /api/..., API key+secret via HTTP Basic auth) and pfSense (REST API v2 /api/v2/..., API key via X-API-Key header). Each target in the config names its own platform, and a name-keyed platform registry selects the API shape, so the same tools work on both and one config can span a mixed estate. The governance harness (audit, policy, token/runaway budget, undo, risk-tiers) is bundled in the package — no external skill-family dependency.\n  All write operations are audited to a local SQLite DB under ~/.firewall-aiops/ (relocatable via FIREWALL_AIOPS_HOME).\n  Credentials: the OPNsense API secret (paired with the API key) or the pfSense API key is stored ENCRYPTED in ~/.firewall-aiops/secrets.enc (Fernet/AES-128 + scrypt-derived key) — never plaintext on disk. Run 'firewall-aiops init' to onboard (it asks for the platform), or 'firewall-aiops secret set <target>' to add one. The store is unlocked by a master password from FIREWALL_AIOPS_MASTER_PASSWORD (non-interactive/MCP/CI) or an interactive prompt (CLI on a TTY). A legacy plaintext env var FIREWALL_<TARGET_NAME_UPPER>_SECRET is still honoured as a fallback with a deprecation warning (migrate with 'firewall-aiops secret migrate'). The secret is presented as HTTP Basic auth (OPNsense) or an X-API-Key header (pfSense) at request time and held only in memory; secrets are never logged or echoed.\n  State-changing operations pass through the @governed_tool decorator (budget guard + audit + a descriptive risk-tier label, not a gate). The high-risk commits (apply_changes, reconfigure) and reboot are risk=high with dry_run; reboot is irreversible. Reversible writes (toggle_rule, add_alias_entry, remove_alias_entry) capture the real fetched before-state and record an inverse undo descriptor. Three writes additionally refuse to destroy the tool's own management path: restart_service refuses the daemon serving this appliance's API, and apply_changes / reconfigure refuse a staged rule set that would provably cut management access.\n  Webhooks: none — no outbound network calls beyond the configured OPNsense / pfSense REST API.\n  SSL: verify_ssl defaults to false-friendly for self-signed lab certs; enable for production.\n  Transitive dependencies: httpx (HTTP client) and the MCP SDK. No post-install scripts or background services.\n---\n\n# Firewall AIops\n\n> **Disclaimer**: Community-maintained open-source project, **not affiliated with, endorsed by, or sponsored by the OPNsense project, Deciso, Netgate, or the pfSense project.** OPNsense, pfSense and Netgate are trademarks of their respective owners. Source at [github.com/AIops-tools/Firewall-AIops](https://github.com/AIops-tools/Firewall-AIops) under the MIT license.\n\nGoverned firewall operations — **35 MCP tools** across **OPNsense** (REST `/api/...`)\nand **pfSense** (REST v2 `/api/v2/...`), every one wrapped with the bundled\n`@governed_tool` harness: a local unified audit log under `~/.firewall-aiops/`,\npolicy engine, token/runaway budget guard, undo-token recording, and\ndescriptive risk-tier labelling. A per-target `platform` field selects the API shape,\nso the same tools work on both firewalls and one config can span a mixed estate. The\nOPNsense API secret / pfSense API key is stored **encrypted**\n(`~/.firewall-aiops/secrets.enc`, Fernet + scrypt) — never plaintext on disk.\n\n> **Standalone**: the governance harness is bundled in the package\n> (`firewall_aiops.governance`) — no external skill-family dependency. Both platform\n> halves have been exercised against real firewalls (OPNsense 26.7, pfSense CE 2.7.2)\n> in addition to the mock suite; `docs/VERIFICATION.md` records what each live run\n> proved, and what remains untested on each platform.\n\n## What This Skill Does\n\n| Group | Tools | Count | R/W |\n|-------|-------|:-----:|:---:|\n| **System** | firmware_status, health_status, interface_status, gateway_status | 4 | read |\n| **Rules** | list_rules, rule_detail, rule_stats, rule_states, pending_changes | 5 | read |\n| **NAT** | nat_port_forwards, nat_outbound, nat_one_to_one | 3 | read |\n| **Aliases** | list_aliases, alias_entries | 2 | read |\n| **VPN** | wireguard_status, openvpn_sessions, ipsec_sas | 3 | read |\n| **DHCP** | dhcp_leases, dhcp_static_mappings | 2 | read |\n| **Diagnostics** | firewall_log, states_table, top_talkers | 3 | read |\n| **Flagship analyses** | gateway_health_rca, rule_hit_and_shadow_analysis, blocked_traffic_rca | 3 | read |\n| **Writes** | toggle_rule, add_alias_entry, remove_alias_entry, kill_states, restart_service | 5 | write (med) |\n| **Writes** | apply_changes, reconfigure, reboot | 3 | write (**high**) |\n| **Undo** | undo_list, undo_apply | 2 | read / write |\n\nThe three flagship analyses are transparent heuristics that report their numbers,\nnever a black-box verdict: `gateway_health_rca` ranks gateways by loss + latency and\nmaps each down/degraded one to a cause + action; `rule_hit_and_shadow_analysis` finds\nnever-hit and shadowed/redundant rules; `blocked_traffic_rca` classifies the noisiest\nblocked sources as scan / brute-force / probe.\n\n## Quick Install\n\n```bash\nuv tool install firewall-aiops\nfirewall-aiops init       # wizard: pick platform (opnsense/pfsense) + encrypted secret\nfirewall-aiops doctor\n```\n\nOr as an OpenClaw plugin, which installs this skill and its MCP server together:\n\n```bash\nopenclaw plugins install clawhub:@zw008/firewall-aiops\nopenclaw skills info firewall-aiops          # expect: Visible to model: yes\n```\n\nNeeds `uvx` on `PATH`: the MCP server is fetched with uv, pinned to this release.\n\n## When to Use This Skill\n\n- Get a one-shot snapshot (`overview` / `firmware_status` / `gateway_status`)\n- Investigate a down/degraded WAN (`gateway_health_rca`) → cause + action\n- Audit the ruleset (`rule_stats` hit counts, `rule_hit_and_shadow_analysis` for\n  never-hit / shadowed / redundant rules)\n- Triage hostile traffic (`firewall_log --action block`, `blocked_traffic_rca`,\n  `top_talkers`)\n- Inspect NAT, aliases, VPN tunnels (WireGuard/OpenVPN/IPsec), and DHCP leases\n- Safely toggle a rule or edit an alias (`toggle_rule` / `add_alias_entry` /\n  `remove_alias_entry`, reversible + undo-recorded), then **make it live** with\n  `apply_changes` (dry-run + audit)\n\n**Do NOT use when** the target is not an OPNsense/pfSense firewall — route hypervisor,\nstorage, backup, cluster, multi-vendor router/switch config, or OT/industrial work to\nthe appropriate other AIops-tools skill.\n\n## Related Skills — Skill Routing\n\n| If the user wants… | Use |\n|--------------------|-----|\n| OPNsense / pfSense firewall ops | **firewall-aiops** (this skill) |\n| A non-firewall platform (hypervisor, storage, backup, cluster, network config, OT edge) | the appropriate **other AIops-tools** skill |\n| Cloud security groups / vendor firewall appliances | out of scope for this tool |\n\n## Common Workflows\n\nThe CLI surface is `init` / `doctor` / `overview` / `log` / `rules` / `secret` / `undo`;\nthe flagship RCAs, NAT / alias / VPN / DHCP reads, and the remaining governed writes are\nMCP tools (start the server with `firewall-aiops mcp`). Recipes below say which is which.\n\n### 1. \"The internet keeps dropping\" — WAN gateway triage\n\n1. `firewall-aiops doctor` → confirm the firewall is reachable and the secret unlocks\n   (a red doctor means you are debugging credentials, not the WAN).\n2. `firewall-aiops overview` → one-shot: firmware/version, gateway + interface health,\n   rule count. Down interfaces sort first.\n3. MCP `gateway_health_rca` → gateways ranked worst-first, each row citing its measured\n   loss % and RTT, mapped to a cause (last-mile loss / congestion / latency / hard down)\n   and a concrete action. The ranking is computed on an internal score that is not\n   returned, so weigh each row's own numbers rather than trusting the order.\n4. If the RCA points at a stuck daemon rather than the circuit, MCP\n   `restart_service(service=\"dpinger\", dry_run=true)` to preview, then re-run for real\n   (medium risk, audited, undo-recorded).\n5. Re-run `firewall-aiops overview` to confirm the gateway came back green.\n6. **Failure branch**: if the restart does not clear it, the gateway is genuinely down\n   upstream — stop touching the firewall and escalate to the ISP. If the restart made\n   things worse, `firewall-aiops undo list` → `firewall-aiops undo apply <id>` reverses\n   the recorded inverse. Do **not** reach for `reboot` (high risk, irreversible, no undo)\n   until a read confirms it is the only remaining option.\n\n### 2. Ruleset spring-clean — retire a rule that never fires\n\n1. MCP `rule_hit_and_shadow_analysis` → enabled rules with 0 evaluations (dead or\n   misordered), rules shadowed by an earlier terminating rule, and exact duplicates —\n   each finding names the offending and the covering rule uuid.\n2. `firewall-aiops rules list --interface wan` → confirm the candidate's position in the\n   evaluation order (a \"never hit\" rule below a broad allow is misordered, not useless).\n3. `firewall-aiops rules show <uuid>` → read the full rule before touching it.\n4. `firewall-aiops rules toggle <uuid> --disable --dry-run` → prints the exact call,\n   changes nothing.\n5. `firewall-aiops rules toggle <uuid> --disable` → double-confirm; the write fetches the\n   rule's real prior enabled flag and records an inverse undo descriptor with an `_undo_id`.\n6. MCP `pending_changes` → read what the commit would actually make live, including\n   whether any staged rule covers the endpoint this tool manages the firewall through.\n   `toggle_rule` already reported `managementImpact` in step 5 if so.\n7. MCP `apply_changes` to commit the staged config — **risk=high**, so set\n   `FIREWALL_AUDIT_APPROVED_BY` and `FIREWALL_AUDIT_RATIONALE` first. It refuses\n   outright if a staged rule would provably cut management access; pass\n   `override=True` only with console access in hand.\n8. **Failure branch**: if traffic breaks after the commit, `firewall-aiops undo apply <id>`\n   restores the rule's prior enabled state, then `apply_changes` again to make the\n   restoration live. The toggle is staged until applied — before step 6 you can simply\n   toggle it back with no commit at all.\n\n### 3. Brute-force against the WAN — block the source with an alias\n\n1. `firewall-aiops log --action block --limit 100` → the raw recent blocks, so you are\n   reading real log lines and not just a summary.\n2. MCP `blocked_traffic_rca` → noisiest blocked sources ranked and classified (port scan,\n   service brute-force on 22/3389/…, or generic probe), each with a recommended action.\n3. MCP `top_talkers` and `states_table` → cross-check whether the source also has\n   *established* states, i.e. whether anything already got through.\n4. MCP `list_aliases` → find your blocklist alias, then `alias_entries(<alias>)` to see\n   what is already in it.\n5. MCP `add_alias_entry(alias=<blocklist>, entry=<src-ip>)` → medium risk, reversible,\n   undo descriptor recorded from the fetched before-state.\n6. MCP `apply_changes` (high risk, audited) to make the alias live, then\n   `kill_states(source=<src-ip>)` to tear down any states the attacker already holds.\n7. **Failure branch**: if you blocked too wide a range and locked out legitimate traffic,\n   MCP `remove_alias_entry` (or `firewall-aiops undo apply <id>`) and `apply_changes`\n   again. If you locked *yourself* out of the web UI, the CLI still works over the API\n   as long as the management rule was untouched — recover there before rebooting.\n\n### 4. Verify and roll back a change window\n\n1. Before the window: `firewall-aiops overview` and `firewall-aiops rules list` → capture\n   the baseline you intend to return to.\n2. Make the staged changes (`rules toggle`, MCP alias edits), each one dry-run first.\n3. MCP `apply_changes` with `FIREWALL_AUDIT_APPROVED_BY` set → commit.\n4. Validate: `firewall-aiops overview`, MCP `gateway_health_rca`, and\n   `firewall-aiops log --action block --limit 50` → make sure the change did not start\n   silently dropping wanted traffic.\n5. `firewall-aiops undo list` → every reversible write in the window, newest first, with\n   its `_undo_id`.\n6. **Failure branch**: roll the window back in reverse order with\n   `firewall-aiops undo apply <id>` per entry, then one final `apply_changes` to commit\n   the rollback. Writes that declare **no** undo (`reboot`, and `apply_changes` itself)\n   cannot be reversed this way — they are audit-only, which is why every reversible edit\n   goes in *before* the commit.\n\n> **Authorization is not this skill's job**: there is no read-only switch, policy\n> file, or approval gate. Whether a write runs is the agent's judgement or the\n> connecting account's permissions — point the tool at an API user without write\n> scope and writes fail at the server. Every call is still audited.\n> `FIREWALL_AUDIT_APPROVED_BY` / `FIREWALL_AUDIT_RATIONALE` are optional audit\n> annotations, recorded when set but never required.\n\n## Governance & Safety\n\n- Every tool is audited to `~/.firewall-aiops/audit.db` (relocatable via\n  `FIREWALL_AIOPS_HOME`).\n- High-risk ops (`apply_changes`, `reconfigure`, `reboot`) are labelled risk=high\n  and audited; `FIREWALL_AUDIT_APPROVED_BY` / `FIREWALL_AUDIT_RATIONALE` are\n  optional audit annotations, recorded when set but never required.\n- Writes support `--dry-run` and double confirmation at the CLI. `reboot` is\n  irreversible (audit only).\n- Reversible writes capture the real fetched before-state and record an inverse\n  descriptor (toggle→toggle-back, add-alias↔remove-alias).\n\n## References\n\n- `references/capabilities.md` — full tool + platform + API-path reference\n- `references/cli-reference.md` — CLI command reference\n- `references/setup-guide.md` — onboarding, credentials, and connectivity\n- `docs/VERIFICATION.md` — live-verification checklist (what the mock suite covers, and what a real-firewall run must prove)\n\nFile v0.12.5:_meta.json\n\n{\n  \"ownerId\": \"kn7b067awq2s97bn3d7p5qfhw5827pxc\",\n  \"slug\": \"firewall-aiops\",\n  \"version\": \"0.12.5\",\n  \"publishedAt\": 1789601135182\n}\n\nFile v0.12.5:references/agent-guardrails.md\n\n# Agent guardrails — running firewall-aiops with a smaller / local model\n\nIf you drive these tools with a local model (Llama, Qwen, Mistral … via Goose,\nOllama, LM Studio, or any OpenAI-compatible runtime), you will get noticeably\nbetter results with a short system prompt. This page gives you one, and — more\nimportantly — tells you which guardrails you **no longer need to write**, because\nthe tool now enforces them itself.\n\nThe distinction matters. A guardrail in a prompt is a request. A guardrail in the\nharness is a guarantee. Anything below that we could move into the harness, we did.\n\n## Authorization is not this tool's job — decide it where it belongs\n\nWhether a write should happen is your decision, or the account's. The tool does\nnot gate it — there is no read-only switch and no approval prompt to configure.\nThe two right places to control read vs write:\n\n- **The account you connect with.** Give the OPNsense/pfSense API user a\n  read-only role. A write then fails at the server, which is the only place the\n  permission actually lives — no skill-side flag can be argued around by a model,\n  but a revoked permission cannot be.\n- **Your agent's system prompt.** If you want an observe-only session, tell the\n  model not to call the write tools (they are clearly tagged `[WRITE]`).\n\nWhat the tool *does* guarantee is that you can always see what happened:\n\n## What the tool now enforces — do not waste prompt budget on these\n\n| You might be tempted to prompt | Why you don't need to |\n|---|---|\n| \"Never restart the web GUI / lock yourself out\" | **Already enforced.** `restart_service` refuses the daemon serving this appliance's own API (`nginx`, `lighttpd`, `configd`, `webgui`, ...), and `apply_changes` / `reconfigure` refuse a staged rule set that would provably cut management access. Both are exact and fail open — see `capabilities.md`. Do not spend prompt budget on it. |\n| \"Don't invent a value when a field is missing\" | OPNsense and pfSense populate different keys for the same concept. A field neither platform returned comes back as `null`, never as `\"\"`. Absent and empty are distinguishable in the payload. |\n| \"Tell me if the output was cut off\" | `firewall_log`, `states_table` and `top_talkers` all return `{\"<items>\": [...], \"returned\": N, \"limit\": L, \"truncated\": true/false}` — the list key is `entries`, `states` and `topTalkers` respectively. Truncation is measured, not guessed from a length coincidence. |\n| \"Make it show the number it judged on\" | Gateway and blocked-source entries carry the numbers they were judged on — `lossPercent` and `rttMs` for a gateway (`lossPct`/`latencyMs` are the *thresholds* they were compared against, reported separately under `thresholds`), `hits`, `distinctPorts` and `topPort` for a blocked source — so those claims can be checked against a figure. `blocked_traffic_rca` orders `topSources` by `hits`, which is in the payload. Rule findings are qualitative: they carry `uuid`, `description`, `interface`, `shadowedBy`/`duplicateOf` and no count, because the hit counter they would be judged on is not always available — `hitCountersUnavailable` says whether it was. |\n| \"Confirm before anything destructive\" | Every write takes `dry_run=True` for a preview that runs the same guards as the real call. ⚠️ **The double confirmation is a CLI feature, and only `toggle_rule` and `undo apply` have CLI commands** — `apply_changes`, `reconfigure`, `reboot`, `restart_service`, `kill_states`, `add_alias_entry` and `remove_alias_entry` are reachable only over MCP, where nothing prompts. Keep your own confirmation for those. |\n| \"Log what you did\" | Every governed call is audited to `~/.firewall-aiops/audit.db` regardless of what the model says it did. |\n\n## What still needs a prompt\n\nThese are model-behaviour problems the harness cannot fix from the outside.\n\n⚠️ **Only one of the three orderings can be checked from the output.** `blocked_traffic_rca`\nsorts `topSources` by `hits`, and `hits` is returned — that order is verifiable.\n`gateway_health_rca` sorts on an internal score that is dropped before the payload is\nreturned, so its order cannot be rechecked; and `rule_hit_and_shadow_analysis` does not order\nits output at all. No entry from these three carries a `rank` or a `severity`.\n\nCopy this into your agent's system prompt:\n\n```text\nYou operate an OPNsense or pfSense firewall through the firewall-aiops MCP tools.\n\nTOOL USE\n- Before answering any question about the current firewall, you MUST call a\n  tool. Never answer from memory or assumption.\n- Actually invoke the tool. Do not describe the call you would make, and do not\n  emit an example JSON response in place of calling it.\n- If a tool call fails, report the real error verbatim. Never fill the gap with\n  a plausible-sounding answer.\n\nREADING RESULTS\n- Read the whole result before concluding. If a result contains a \"truncated\"\n  field that is true, say so and re-run with a higher limit instead of treating\n  the partial result as complete.\n- Of the three RCAs, only `blocked_traffic_rca`'s order is checkable (by `hits`). Do not read\n  priority off the position of a gateway finding, and do not look for a number on a rule\n  finding — there is none; read `hitCountersUnavailable` to see whether \"never hit\" was even\n  measurable.\n- A null field means neither platform returned that value. Report it as \"not\n  available\" — never infer it. In particular, a rule with a null \"interface\" is\n  not a rule on an interface named \"none\".\n- Report values exactly as returned. Do not normalise, translate, or prettify\n  rule actions, gateway statuses, or interface names.\n- A gateway whose status is \"none\" is unmonitored, not down. A gateway with no\n  status field at all is unknown — say so rather than calling it healthy.\n\n- Only `toggle_rule` has a CLI command. `apply_changes`, `reconfigure`, `reboot`,\n  `restart_service`, `kill_states` and the alias writes are MCP-only and nothing will ask\n  you to confirm them: call with `dry_run=True` first and wait for an explicit go-ahead.\n\nSCOPE\n- Separate observation from interpretation. State what the tools returned, then\n  any interpretation, clearly marked as such.\n- Do not assert that traffic is being blocked by a specific rule unless a log\n  entry or the shadow analysis actually names that rule.\n- Do not add generic firewall advice that does not follow from the tool output.\n- Do not confuse a rule UUID with an alias name, an interface name (wan, lan,\n  opt1) with its description, or a gateway name with its monitor IP.\n- OPNsense and pfSense are different platforms with different API shapes. Do not\n  suggest an OPNsense-only action on a pfSense target; the target's platform is\n  reported in the overview.\n\nCHANGES ARE TWO-STEP\n- On OPNsense, editing a rule stages it; nothing takes effect until\n  apply_changes is called. Never report a change as live before that.\n```\n\n## Recommended setup for a local model\n\nStart with a connection that *cannot* write, verify, and widen the account's\npermission only when you trust the setup. A read-only role is a sensible default\nfor a firewall specifically: a mistaken `toggle_rule` or `reboot` on the box that\ncarries your management session locks you out of the thing you were trying to fix.\n\n```bash\n# Give the OPNsense/pfSense API user a read-only role, then:\nfirewall-aiops doctor\n```\n\nOptionally annotate the audit trail with who is operating and why — recorded on\nevery row, never required:\n\n```bash\nexport FIREWALL_AUDIT_APPROVED_BY=\"your.name@example.com\"\nexport FIREWALL_AUDIT_RATIONALE=\"scheduled maintenance window 2026-07-20\"\n```\n\n## If your model still struggles\n\nSome behaviours are model-capacity limits rather than prompt problems:\n\n- **Multi-tool workflows time out or drift.** Prefer the RCA tools\n  (`gateway_health_rca`, `blocked_traffic_rca`,\n  `rule_hit_and_shadow_analysis`) — they do the multi-step correlation inside\n  one call, so the model does not have to chain reads and keep rule UUIDs\n  straight.\n- **The model ignores later tool results in a long context.** The firewall log\n  and state table are the two big payloads here; ask narrower questions and use\n  `--limit` / `top` deliberately rather than pulling the whole state table.\n- **The model describes calls instead of making them.** This is usually a\n  runtime/tool-calling-format mismatch, not a prompt problem — check that your\n  client advertises the tools in the format your model was trained on.\n\nFeedback on running this with a specific local model is genuinely useful —\nopen an issue at\n[github.com/AIops-tools/Firewall-AIops](https://github.com/AIops-tools/Firewall-AIops/issues)\nwith the model, runtime, and what went wrong.\n\nFile v0.12.5:references/capabilities.md\n\n# firewall-aiops capabilities\n\n> **35 MCP tools** (26 read, 9 write) across OPNsense (REST `/api/...`, API key+secret\n> via HTTP Basic) and pfSense (REST v2 `/api/v2/...`, API key via `X-API-Key`). The\n> concrete REST paths below are modelled from each project's public API and have not\n> yet been exercised against a live firewall — see `docs/VERIFICATION.md`.\n\nA per-target `platform` field (`opnsense` / `pfsense`) selects the API shape; the same\ntool name resolves to the right path on each firewall via the platform registry.\n\n## System (read)\n\n| Tool | OPNsense path | pfSense path | Returns |\n|------|---------------|--------------|---------|\n| `firmware_status` | `/api/core/firmware/status` | `/api/v2/system/version` | version, product, updates available |\n| `health_status` | `/api/diagnostics/system/systemInformation` | `/api/v2/status/system` | hostname, uptime, CPU %, mem %, load |\n| `interface_status` | `/api/diagnostics/interface/getInterfaceNames` | `/api/v2/status/interfaces` | interfaces with link status + address (down first) |\n| `gateway_status` | `/api/routes/gateway/status` | `/api/v2/status/gateways` | gateways with status, loss %, RTT |\n\n## Rules (read)\n\n| Tool | OPNsense path | pfSense path | Returns |\n|------|---------------|--------------|---------|\n| `list_rules` | `/api/firewall/filter/searchRule` | `/api/v2/firewall/rules` | filter rules normalized (uuid, enabled, action, if, src/dst, evaluations) |\n| `rule_detail` | `/api/firewall/filter/getRule/{uuid}` | `/api/v2/firewall/rule?id=` | one rule's full detail |\n| `rule_stats` | `/api/diagnostics/firewall/pfStatistics` | `/api/v2/firewall/rules` | per-rule hit counts / evaluations, busiest first |\n| `rule_states` | `/api/diagnostics/firewall/queryStates` | `/api/v2/firewall/states` | active state-table entries tied to rules |\n| `pending_changes` | (derived from `searchRule`) | (derived from `firewall/rules`) | the staged rule set `apply_changes` would commit + its lockout assessment |\n\n## NAT (read)\n\n| Tool | Returns |\n|------|---------|\n| `nat_port_forwards` | inbound port-forward (DNAT) rules |\n| `nat_outbound` | outbound (source) NAT mappings |\n| `nat_one_to_one` | 1:1 NAT mappings (external ↔ internal) |\n\n## Aliases (read)\n\n| Tool | Returns |\n|------|---------|\n| `list_aliases` | all aliases (name, type, description, member count) |\n| `alias_entries` | the member entries (hosts/networks/ports) of one alias |\n\n## VPN (read)\n\n| Tool | Returns |\n|------|---------|\n| `wireguard_status` | WireGuard peers with connected state, last handshake, transfer |\n| `openvpn_sessions` | OpenVPN sessions / connected clients (name, address, bytes) |\n| `ipsec_sas` | IPsec security associations (phase-1/phase-2) with state |\n\n## DHCP (read)\n\n| Tool | Returns |\n|------|---------|\n| `dhcp_leases` | active DHCP leases (IP, MAC, hostname, state); `online_only` filter |\n| `dhcp_static_mappings` | DHCP static (reserved) mappings (MAC ↔ IP) |\n\n## Diagnostics (read)\n\n| Tool | Returns |\n|------|---------|\n| `firewall_log` | recent firewall-log entries, optional `action` filter (pass/block/…) |\n| `states_table` | active pf state-table entries |\n| `top_talkers` | busiest source hosts, aggregated from the state table by bytes |\n\n## Flagship analyses (read, pure heuristics)\n\n| Tool | What it does |\n|------|--------------|\n| `gateway_health_rca` | rank gateways by loss (x10) + latency; flag down (status down / 100% loss) and degraded (over threshold); map each to a cause + action. Pass `gateways=` for pure analysis or a target to pull live |\n| `rule_hit_and_shadow_analysis` | never-hit enabled rules (0 evaluations), rules shadowed by an earlier terminating rule, and exact duplicates; each finding names the offending/covering rule uuid |\n| `blocked_traffic_rca` | aggregate blocked log rows by source; classify as port scan (≥10 distinct ports), service brute-force/probe (busy sensitive port 22/3389/…), or generic; with an action |\n\n## Writes (governed)\n\n| Tool | Risk | Path(s) | Notes |\n|------|------|---------|-------|\n| `toggle_rule` | **med** | OPNsense `toggleRule/{uuid}/{0\\|1}`; pfSense PATCH `firewall/rule` | reads the rule first; records undo (restore prior enabled). Staged — run `apply_changes` |\n| `add_alias_entry` | **med** | OPNsense `alias_util/add/{name}`; pfSense `firewall/alias` | captures prior entries; undo removes the added entry |\n| `remove_alias_entry` | **med** | OPNsense `alias_util/delete/{name}`; pfSense `firewall/alias` | captures prior entries; undo adds it back |\n| `kill_states` | **med** | `diagnostics/…/killStates` / `firewall/states` (DELETE, query-filtered) | flush pf states (optionally one source IP) |\n| `restart_service` | **med** | `service/restart/{service}` | restart a firewall service; **refuses** the daemon serving this appliance's own API |\n| `apply_changes` | **HIGH** | `filter/apply` / `firewall/apply` | commit staged config — makes edits live; `dry_run` returns the staged set; **refuses** a provable lockout (`override=True` to force); audited |\n| `reconfigure` | **HIGH** | `filter/savepoint` / `firewall/apply` | reload/commit a subsystem; `dry_run` + audited |\n| `reboot` | **HIGH** | `core/system/reboot` / `diagnostics/reboot` | IRREVERSIBLE — audit only, no undo; `dry_run` |\n\n## Out of scope (v0.1)\n\n- Creating/deleting rules, aliases, or NAT entries from scratch (only toggle + alias\n  entry add/remove today).\n- Cloud security groups and vendor firewall appliances.\n- **Missing something? Open an issue or PR** — contributions welcome.\n\n## Self-lockout guards\n\nA firewall is the one appliance where a routine write severs the connection\ncarrying it — and the recorded undo needs that same connection. Three writes\nrefuse rather than let that happen. All of them are **exact** and **fail open**.\n\n### `restart_service`\n\nRefuses the daemon that answers this platform's own management API — OPNsense\n`nginx` / `configd` / `php-fpm`, pfSense `lighttpd` / `php-fpm`, plus the\ngeneric aliases (`webgui`, `web`, `webserver`, `gui`, `api`) an agent told\n\"restart the web service\" would actually pass. The list lives on the `Platform`\ndescriptor, which already knows which daemon serves its own URLs. Matching is\nexact and case-insensitive; an unrecognised service name is never blocked on a\nguess, so `unbound`, `dhcpd`, `openvpn`, `ipsec` and friends restart normally.\n\n### `apply_changes` / `reconfigure filter`\n\nBoth read the staged rule set first (see `pending_changes`) and refuse when\ncommitting it would provably cut management access. Two mirror-image shapes are\ndangerous:\n\n- a **disabled `pass`** rule that permits management access — applying removes the permit;\n- an **enabled `block`** rule that covers it — applying starts blocking.\n\n\"Provably\" means a literal match on **both** the management host and port.\nEverything short of that fails open with a named warning and proceeds:\n\n| Warning | Meaning |\n|---|---|\n| `ALIAS_DESTINATION` | destination is an alias; it may resolve to the management address |\n| `ANY_DESTINATION` | destination is `any` / a CIDR that may contain the host |\n| `ANY_PORT` | no destination port — may include the management port |\n| `PORT_RANGE` | port expression could not be parsed to a range |\n| `INTERFACE_GROUP` | rule is on `any` / an interface group |\n\n`override=True` proceeds despite a certain finding — for operators with console\naccess who mean it. A rule set that cannot be READ does not block either, but is\nreported as `assessed: false` with the error rather than as a clean bill of\nhealth (a failed probe is not \"nothing pending\").\n\n### `toggle_rule`\n\nRuns the same assessment at staging time — the cheapest point to warn, since the\nrule row is already in hand — and reports `managementImpact` in both directions.\nAdvisory only: staging is never blocked, because `apply_changes` is where the\nchange becomes real and where the refusal lives.\n\n### `dry_run` does not bypass the guards\n\nA `dry_run` whose honest answer is \"this would be refused\" **refuses**. Previewing\nsuccess for a call that is then refused is the preview being wrong, and a weak\nmodel reads the later refusal as transient and retries it. So:\n\n- `apply_changes(dry_run=True)` / `reconfigure(subsystem=\"filter\", dry_run=True)`\n  run the lockout guard before returning, and honour `override=True` on both paths.\n- `restart_service(dry_run=True)` refuses an API-serving service name.\n\n- `toggle_rule(dry_run=True)` reads the rule and reports the same\n  `managementImpact` the real call would.\n\nFail-open semantics are **identical** on both paths — a dry-run never refuses\nwhat the real call would allow.\n\nThe CLI's `rules toggle --dry-run` routes through the governed twin, so it\nreaches the same assessment **and** records the same audit row. The line's\ninvariant is: **a dry_run MAY read; it must never write.** A preview that cannot\nread cannot answer \"would this be refused?\", so reads are expected; the mutating\nPOST/PATCH is the thing that must never happen. (`apply_changes`,\n`reconfigure`, `restart_service`, `kill_states` and `reboot` have no CLI command\n— they are MCP-only — so `rules toggle` is the whole CLI write surface.)\n\n### Two pfSense reads depend on the pfSense-pkg-RESTAPI version\n\n`wireguard_status` and `dhcp_static_mappings` read endpoints that newer\npfSense-pkg-RESTAPI builds serve and older ones do not (`/api/v2/status/wireguard/peers`,\n`/api/v2/services/dhcp_server/static_mappings`). On a build that predates them the\ncall returns a 404 error payload naming the exact path — it is not \"WireGuard is\nnot configured\". Upgrade the package on the firewall to get those surfaces.\nEverything else in this table was exercised against pfSense CE 2.7.2 with\npfSense-pkg-RESTAPI 2.4_3.\n\n### `kill_states` is a lost response, not a lockout\n\nFlushing the pf state table drops the state entry for this tool's own\nconnection, so the call can appear to fail even though the flush ran. Access is\nNOT lost: the permitting rule is untouched and the next call re-establishes\nstate. The dry-run says so in `sessionImpact`, and the result repeats it in\n`note`. **Do not retry blindly** — the flush is likely already done.\n\n### Reversible writes survive a lost response\n\n`toggle_rule`, `add_alias_entry` and `remove_alias_entry` stash their before-state\nvia `capture_prior_state()` immediately before the mutating request. If the\nresponse is lost, the harness records `status=unknown` (not a false `error`) and\ncan still record the inverse, flagged `effectVerified=false`. The irreversible\nwrites (`apply_changes`, `reconfigure`, `restart_service`, `kill_states`,\n`reboot`) declare no inverse, so they capture nothing — there is nothing to\nreplay.\n\nFile v0.12.5:references/cli-reference.md\n\n# firewall-aiops CLI reference\n\n> Covers OPNsense (REST `/api/...`) and pfSense (REST v2 `/api/v2/...`). Responses are\n> validated against mocks; see `docs/VERIFICATION.md` for the live-run checklist.\n\n## Setup & diagnostics\n\n```bash\nfirewall-aiops init                      # interactive wizard (asks for the platform: opnsense/pfsense)\nfirewall-aiops doctor                    # check config, secrets, connectivity\n                                         #   firmware/version query on both platforms\nfirewall-aiops doctor --skip-auth        # config/secret checks only (no network)\nfirewall-aiops mcp                       # start the MCP server (stdio)\n```\n\n## Secrets (encrypted store)\n\n```bash\nfirewall-aiops secret set <target> [--value <secret>]  # store OPNsense secret / pfSense key (hidden prompt if no --value)\nfirewall-aiops secret list                             # list target names with a stored secret (values never shown)\nfirewall-aiops secret rm <target>                      # delete a stored secret\nfirewall-aiops secret migrate                          # import legacy plaintext .env into the encrypted store\nfirewall-aiops secret rotate-password                  # re-encrypt under a new master password\n```\n\n## Overview & rules\n\n```bash\nfirewall-aiops overview                        # one-shot: version + gateway/interface health + rule count\nfirewall-aiops rules list [--interface wan]    # list filter rules (optionally on one interface)\nfirewall-aiops rules show <uuid>               # one rule's full detail\nfirewall-aiops rules toggle <uuid> --disable   # governed write: dry-run + double-confirm\nfirewall-aiops rules toggle <uuid> --enable --dry-run\n```\n\n## Firewall log\n\n```bash\nfirewall-aiops log                             # recent firewall-log entries\nfirewall-aiops log --action block --limit 50   # only blocked traffic\n```\n\n## Notes\n\n- `--target/-t` selects a named target from `config.yaml`; omit for the default (first).\n- `overview`, `rules`, and `log` are the CLI subset; the full read surface (NAT,\n  aliases, VPN, DHCP, diagnostics), the three flagship analyses, and the remaining\n  governed writes (alias entry add/remove, kill_states, restart_service, apply_changes,\n  reconfigure, reboot) are exposed through the MCP server (`firewall-aiops mcp`).\n- High-risk writes (`apply_changes`, `reconfigure`, `reboot`) are labelled risk=high\n  and audited. `FIREWALL_AUDIT_APPROVED_BY` (and `FIREWALL_AUDIT_RATIONALE`) are\n  optional audit annotations, recorded when set but never required.\n\nFile v0.12.5:references/setup-guide.md\n\n# firewall-aiops setup & security guide\n\n> Both **OPNsense** (fully open-source) and **pfSense CE** (free) are self-hostable, so\n> a home lab is the easiest place to run the live checklist in `docs/VERIFICATION.md`.\n> The modelled REST paths are the largest verification debt.\n\n## 1. Install\n\n```bash\nuv tool install firewall-aiops       # or: pipx install firewall-aiops\n```\n\n## 2. What you need per firewall\n\n- **OPNsense** — an **API key + secret** pair (System → Access → Users → edit a user →\n  API keys → create). firewall-aiops talks to the REST API on port **443** and presents\n  the key+secret as HTTP Basic auth. Enable the OPNsense web GUI / API for the account.\n- **pfSense** — the **REST API v2** package (pfSense-pkg-RESTAPI) installed and an **API\n  key** issued by it. The API is under `/api/v2/...` on port **443**; the key is sent in\n  an `X-API-Key` header.\n\n## 3. Onboard with the wizard\n\n```bash\nfirewall-aiops init\n```\n\nThe wizard asks, per target, for the **platform** (`opnsense` / `pfsense`), the\n**host**, the **port** (default 443), the **OPNsense API key** (OPNsense only, saved as\n`username`), and the **secret** — the OPNsense API secret or the pfSense API key.\nNon-secret connection details go to `~/.firewall-aiops/config.yaml`; the secret is\nstored **encrypted** in `~/.firewall-aiops/secrets.enc`.\n\nExample `config.yaml`:\n\n```yaml\ntargets:\n  - name: fw1\n    platform: opnsense\n    host: 192.0.2.1\n    port: 443\n    username: <opnsense-api-key>\n    verify_ssl: true      # the default; set false ONLY for self-signed lab certs\n  - name: edge\n    platform: pfsense\n    host: 192.0.2.2\n    port: 443\n    verify_ssl: true\n    # scheme: http        # https is the default; set http ONLY when the GUI is\n    #                     # published over plain HTTP behind a proxy terminating TLS\n```\n\n## 4. Master password (for non-interactive / MCP use)\n\nThe encrypted store is unlocked by a master password. For the MCP server, CI, or cron,\nexport it so no prompt is needed:\n\n```bash\nexport FIREWALL_AIOPS_MASTER_PASSWORD='...'\n```\n\nOn a TTY the CLI prompts interactively if the env var is unset.\n\n## 5. Verify connectivity\n\n```bash\nfirewall-aiops doctor\n```\n\n`doctor` checks the config file, the encrypted store and its permissions, that each\ntarget has a secret, and (unless `--skip-auth`) live connectivity — a firmware/version\nquery on both platforms.\n\n## Security notes\n\n- The secret (OPNsense API secret / pfSense API key) is **never** written to disk in\n  plaintext — only the scrypt salt and Fernet ciphertext are stored (chmod 600). The\n  master password is never stored.\n- A legacy plaintext env var `FIREWALL_<TARGET_NAME_UPPER>_SECRET` is honoured as a\n  fallback with a deprecation warning (migrate with `firewall-aiops secret migrate`).\n- The secret is presented as HTTP Basic auth (OPNsense) or an `X-API-Key` header\n  (pfSense) at request time and held only in memory; secrets are never logged or echoed.\n- `verify_ssl` defaults to true; set `false` only for self-signed lab certificates.\n- `scheme` defaults to `https`; set `http` only when the GUI is published over plain\n  HTTP behind a proxy that terminates TLS for it.\n- Every MCP tool is audited to `~/.firewall-aiops/audit.db` (relocatable via\n  `FIREWALL_AIOPS_HOME`). High-risk writes (`apply_changes`, `reconfigure`, `reboot`)\n  are labelled risk=high and audited; `FIREWALL_AUDIT_APPROVED_BY` +\n  `FIREWALL_AUDIT_RATIONALE` are optional audit annotations, recorded when set but\n  never required.\n- No webhooks, no telemetry, no outbound calls beyond the configured OPNsense / pfSense\n  REST API. No post-install scripts or background services.\n\nFile v0.12.5:skill-card.md\n\n## Description:\n\nFirewall AIops helps agents operate OPNsense and pfSense firewalls, covering health checks, rules, NAT, aliases, VPN, DHCP, logs, RCA workflows, and governed write operations.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[zw008](https://clawhub.ai/user/zw008)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nNetwork administrators, SREs, and security engineers use this skill to inspect and troubleshoot OPNsense or pfSense firewalls, then plan or execute governed changes such as rule toggles, alias updates, state kills, service restarts, commits, and reboots.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: High-impact firewall write actions can change live rules, aliases, states, services, or appliance availability without a built-in approval gate.\n\nMitigation: Use a read-only OPNsense or pfSense API account by default, grant write permissions only for planned change windows, and require explicit operator approval before MCP write calls.\n\nRisk: A trusted agent or over-permissioned account could apply disruptive firewall changes.\n\nMitigation: Install the skill only for trusted agents and accounts, review dry-run output first, and keep local audit annotations for change accountability.\n\nRisk: Firewall credentials and backups under ~/.firewall-aiops could expose operational access if mishandled.\n\nMitigation: Protect ~/.firewall-aiops and backups, avoid broadly visible master-password environment variables, and migrate away from legacy plaintext secret fallbacks.\n\nRisk: TLS configuration guidance is mixed across artifacts and weak verification can hide man-in-the-middle risk.\n\nMitigation: Verify TLS settings during setup and use certificate verification for production firewall connections.\n\n## Reference(s):\n\n- [Capabilities reference](references/capabilities.md)\n- [CLI reference](references/cli-reference.md)\n- [Setup and security guide](references/setup-guide.md)\n- [Agent guardrails](references/agent-guardrails.md)\n- [Project homepage](https://github.com/AIops-tools/Firewall-AIops)\n- [ClawHub skill page](https://clawhub.ai/zw008/skills/firewall-aiops)\n\n## Skill Output:\n\n**Output Type(s):** [Analysis, Markdown, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown with inline shell commands and structured firewall-operation guidance]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May include firewall status summaries, RCA findings, dry-run recommendations, audit guidance, and governed write proposals.]\n\n## Skill Version(s):\n\n0.12.5 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.12.4: 7 files, 20005 bytes\n\nFiles: references/agent-guardrails.md (6900b), references/capabilities.md (10693b), references/cli-reference.md (2530b), references/setup-guide.md (3664b), skill-card.md (2564b), SKILL.md (16120b), _meta.json (134b)\n\nFile v0.12.4:SKILL.md\n\n---\nname: firewall-aiops\nslug: firewall-aiops\ndisplayName: \"Firewall AIops\"\nsummary: \"Governed OPNsense + pfSense firewall ops: rules, NAT, VPN, DHCP, RCA. 35 tools.\"\nlicense: MIT\nhomepage: https://github.com/AIops-tools/Firewall-AIops\ntags: [aiops, mcp, governance, firewall]\ndescription: >\n  Use this skill whenever the user needs to operate an OPNsense or pfSense firewall — a one-shot overview, firmware/health, interfaces and gateways, firewall rules with hit-counts and shadow analysis, NAT (port-forward/outbound/1:1), aliases and their entries, VPN (WireGuard/OpenVPN/IPsec), DHCP leases and static mappings, the firewall log and state table, three flagship RCAs (gateway health, rule hit/shadow, blocked traffic), and governed writes (toggle a rule, add/remove an alias entry, kill states, restart a service, apply/reconfigure to make edits live, reboot).\n  Always use this skill for \"OPNsense\", \"pfSense\", \"firewall rule\", \"port forward\", \"NAT\", \"alias\", \"WireGuard\", \"OpenVPN\", \"IPsec\", \"DHCP lease\", \"firewall log\", \"blocked traffic\", \"why is my WAN down\", \"gateway loss/latency\", \"unused / shadowed rules\", \"apply firewall changes\", \"reboot the firewall\" when the context is an OPNsense/pfSense firewall.\n  Do NOT use when the target is something other than an OPNsense/pfSense firewall (a hypervisor, storage appliance, backup product, container-orchestration cluster, multi-vendor router/switch config, or OT/industrial equipment) — route those to the appropriate other AIops-tools skill. Cloud security groups and vendor firewall appliances are out of scope.\n  Governed firewall operations with a built-in governance harness (audit, policy, token budget, undo, risk-tiers). Live-verified against real OPNsense 26.7 and pfSense CE 2.7.2 on top of the mock test suite; see docs/VERIFICATION.md for exactly what each run proved and what is still untested.\ninstaller:\n  kind: uv\n  package: firewall-aiops\nargument-hint: \"[a rule/alias id, an IP, or describe your firewall task]\"\nallowed-tools:\n  - Bash\nmetadata: {\"openclaw\":{\"requires\":{\"anyBins\":[\"firewall-aiops\",\"uvx\"]},\"optional\":{\"env\":[\"FIREWALL_AIOPS_CONFIG\",\"FIREWALL_AIOPS_MASTER_PASSWORD\"]},\"homepage\":\"https://github.com/AIops-tools/Firewall-AIops\",\"emoji\":\"🛡️\",\"os\":[\"macos\",\"linux\"]}}\ncompatibility: >\n  Standalone, self-governed firewall operations across OPNsense (REST API /api/..., API key+secret via HTTP Basic auth) and pfSense (REST API v2 /api/v2/..., API key via X-API-Key header). Each target in the config names its own platform, and a name-keyed platform registry selects the API shape, so the same tools work on both and one config can span a mixed estate. The governance harness (audit, policy, token/runaway budget, undo, risk-tiers) is bundled in the package — no external skill-family dependency.\n  All write operations are audited to a local SQLite DB under ~/.firewall-aiops/ (relocatable via FIREWALL_AIOPS_HOME).\n  Credentials: the OPNsense API secret (paired with the API key) or the pfSense API key is stored ENCRYPTED in ~/.firewall-aiops/secrets.enc (Fernet/AES-128 + scrypt-derived key) — never plaintext on disk. Run 'firewall-aiops init' to onboard (it asks for the platform), or 'firewall-aiops secret set <target>' to add one. The store is unlocked by a master password from FIREWALL_AIOPS_MASTER_PASSWORD (non-interactive/MCP/CI) or an interactive prompt (CLI on a TTY). A legacy plaintext env var FIREWALL_<TARGET_NAME_UPPER>_SECRET is still honoured as a fallback with a deprecation warning (migrate with 'firewall-aiops secret migrate'). The secret is presented as HTTP Basic auth (OPNsense) or an X-API-Key header (pfSense) at request time and held only in memory; secrets are never logged or echoed.\n  State-changing operations pass through the @governed_tool decorator (budget guard + audit + a descriptive risk-tier label, not a gate). The high-risk commits (apply_changes, reconfigure) and reboot are risk=high with dry_run; reboot is irreversible. Reversible writes (toggle_rule, add_alias_entry, remove_alias_entry) capture the real fetched before-state and record an inverse undo descriptor. Three writes additionally refuse to destroy the tool's own management path: restart_service refuses the daemon serving this appliance's API, and apply_changes / reconfigure refuse a staged rule set that would provably cut management access.\n  Webhooks: none — no outbound network calls beyond the configured OPNsense / pfSense REST API.\n  SSL: verify_ssl defaults to false-friendly for self-signed lab certs; enable for production.\n  Transitive dependencies: httpx (HTTP client) and the MCP SDK. No post-install scripts or background services.\n---\n\n# Firewall AIops\n\n> **Disclaimer**: Community-maintained open-source project, **not affiliated with, endorsed by, or sponsored by the OPNsense project, Deciso, Netgate, or the pfSense project.** OPNsense, pfSense and Netgate are trademarks of their respective owners. Source at [github.com/AIops-tools/Firewall-AIops](https://github.com/AIops-tools/Firewall-AIops) under the MIT license.\n\nGoverned firewall operations — **35 MCP tools** across **OPNsense** (REST `/api/...`)\nand **pfSense** (REST v2 `/api/v2/...`), every one wrapped with the bundled\n`@governed_tool` harness: a local unified audit log under `~/.firewall-aiops/`,\npolicy engine, token/runaway budget guard, undo-token recording, and\ndescriptive risk-tier labelling. A per-target `platform` field selects the API shape,\nso the same tools work on both firewalls and one config can span a mixed estate. The\nOPNsense API secret / pfSense API key is stored **encrypted**\n(`~/.firewall-aiops/secrets.enc`, Fernet + scrypt) — never plaintext on disk.\n\n> **Standalone**: the governance harness is bundled in the package\n> (`firewall_aiops.governance`) — no external skill-family dependency. Both platform\n> halves have been exercised against real firewalls (OPNsense 26.7, pfSense CE 2.7.2)\n> in addition to the mock suite; `docs/VERIFICATION.md` records what each live run\n> proved, and what remains untested on each platform.\n\n## What This Skill Does\n\n| Group | Tools | Count | R/W |\n|-------|-------|:-----:|:---:|\n| **System** | firmware_status, health_status, interface_status, gateway_status | 4 | read |\n| **Rules** | list_rules, rule_detail, rule_stats, rule_states, pending_changes | 5 | read |\n| **NAT** | nat_port_forwards, nat_outbound, nat_one_to_one | 3 | read |\n| **Aliases** | list_aliases, alias_entries | 2 | read |\n| **VPN** | wireguard_status, openvpn_sessions, ipsec_sas | 3 | read |\n| **DHCP** | dhcp_leases, dhcp_static_mappings | 2 | read |\n| **Diagnostics** | firewall_log, states_table, top_talkers | 3 | read |\n| **Flagship analyses** | gateway_health_rca, rule_hit_and_shadow_analysis, blocked_traffic_rca | 3 | read |\n| **Writes** | toggle_rule, add_alias_entry, remove_alias_entry, kill_states, restart_service | 5 | write (med) |\n| **Writes** | apply_changes, reconfigure, reboot | 3 | write (**high**) |\n| **Undo** | undo_list, undo_apply | 2 | read / write |\n\nThe three flagship analyses are transparent heuristics that report their numbers,\nnever a black-box verdict: `gateway_health_rca` ranks gateways by loss + latency and\nmaps each down/degraded one to a cause + action; `rule_hit_and_shadow_analysis` finds\nnever-hit and shadowed/redundant rules; `blocked_traffic_rca` classifies the noisiest\nblocked sources as scan / brute-force / probe.\n\n## Quick Install\n\n```bash\nuv tool install firewall-aiops\nfirewall-aiops init       # wizard: pick platform (opnsense/pfsense) + encrypted secret\nfirewall-aiops doctor\n```\n\nOr as an OpenClaw plugin, which installs this skill and its MCP server together:\n\n```bash\nopenclaw plugins install clawhub:@zw008/firewall-aiops\nopenclaw skills info firewall-aiops          # expect: Visible to model: yes\n```\n\nNeeds `uvx` on `PATH`: the MCP server is fetched with uv, pinned to this release.\n\n## When to Use This Skill\n\n- Get a one-shot snapshot (`overview` / `firmware_status` / `gateway_status`)\n- Investigate a down/degraded WAN (`gateway_health_rca`) → cause + action\n- Audit the ruleset (`rule_stats` hit counts, `rule_hit_and_shadow_analysis` for\n  never-hit / shadowed / redundant rules)\n- Triage hostile traffic (`firewall_log --action block`, `blocked_traffic_rca`,\n  `top_talkers`)\n- Inspect NAT, aliases, VPN tunnels (WireGuard/OpenVPN/IPsec), and DHCP leases\n- Safely toggle a rule or edit an alias (`toggle_rule` / `add_alias_entry` /\n  `remove_alias_entry`, reversible + undo-recorded), then **make it live** with\n  `apply_changes` (dry-run + audit)\n\n**Do NOT use when** the target is not an OPNsense/pfSense firewall — route hypervisor,\nstorage, backup, cluster, multi-vendor router/switch config, or OT/industrial work to\nthe appropriate other AIops-tools skill.\n\n## Related Skills — Skill Routing\n\n| If the user wants… | Use |\n|--------------------|-----|\n| OPNsense / pfSense firewall ops | **firewall-aiops** (this skill) |\n| A non-firewall platform (hypervisor, storage, backup, cluster, network config, OT edge) | the appropriate **other AIops-tools** skill |\n| Cloud security groups / vendor firewall appliances | out of scope for this tool |\n\n## Common Workflows\n\nThe CLI surface is `init` / `doctor` / `overview` / `log` / `rules` / `secret` / `undo`;\nthe flagship RCAs, NAT / alias / VPN / DHCP reads, and the remaining governed writes are\nMCP tools (start the server with `firewall-aiops mcp`). Recipes below say which is which.\n\n### 1. \"The internet keeps dropping\" — WAN gateway triage\n\n1. `firewall-aiops doctor` → confirm the firewall is reachable and the secret unlocks\n   (a red doctor means you are debugging credentials, not the WAN).\n2. `firewall-aiops overview` → one-shot: firmware/version, gateway + interface health,\n   rule count. Down interfaces sort first.\n3. MCP `gateway_health_rca` → gateways ranked worst-first, each row citing its measured\n   loss % and RTT, mapped to a cause (last-mile loss / congestion / latency / hard down)\n   and a concrete action.\n4. If the RCA points at a stuck daemon rather than the circuit, MCP\n   `restart_service(service=\"dpinger\", dry_run=true)` to preview, then re-run for real\n   (medium risk, audited, undo-recorded).\n5. Re-run `firewall-aiops overview` to confirm the gateway came back green.\n6. **Failure branch**: if the restart does not clear it, the gateway is genuinely down\n   upstream — stop touching the firewall and escalate to the ISP. If the restart made\n   things worse, `firewall-aiops undo list` → `firewall-aiops undo apply <id>` reverses\n   the recorded inverse. Do **not** reach for `reboot` (high risk, irreversible, no undo)\n   until a read confirms it is the only remaining option.\n\n### 2. Ruleset spring-clean — retire a rule that never fires\n\n1. MCP `rule_hit_and_shadow_analysis` → enabled rules with 0 evaluations (dead or\n   misordered), rules shadowed by an earlier terminating rule, and exact duplicates —\n   each finding names the offending and the covering rule uuid.\n2. `firewall-aiops rules list --interface wan` → confirm the candidate's position in the\n   evaluation order (a \"never hit\" rule below a broad allow is misordered, not useless).\n3. `firewall-aiops rules show <uuid>` → read the full rule before touching it.\n4. `firewall-aiops rules toggle <uuid> --disable --dry-run` → prints the exact call,\n   changes nothing.\n5. `firewall-aiops rules toggle <uuid> --disable` → double-confirm; the write fetches the\n   rule's real prior enabled flag and records an inverse undo descriptor with an `_undo_id`.\n6. MCP `pending_changes` → read what the commit would actually make live, including\n   whether any staged rule covers the endpoint this tool manages the firewall through.\n   `toggle_rule` already reported `managementImpact` in step 5 if so.\n7. MCP `apply_changes` to commit the staged config — **risk=high**, so set\n   `FIREWALL_AUDIT_APPROVED_BY` and `FIREWALL_AUDIT_RATIONALE` first. It refuses\n   outright if a staged rule would provably cut management access; pass\n   `override=True` only with console access in hand.\n8. **Failure branch**: if traffic breaks after the commit, `firewall-aiops undo apply <id>`\n   restores the rule's prior enabled state, then `apply_changes` again to make the\n   restoration live. The toggle is staged until applied — before step 6 you can simply\n   toggle it back with no commit at all.\n\n### 3. Brute-force against the WAN — block the source with an alias\n\n1. `firewall-aiops log --action block --limit 100` → the raw recent blocks, so you are\n   reading real log lines and not just a summary.\n2. MCP `blocked_traffic_rca` → noisiest blocked sources ranked and classified (port scan,\n   service brute-force on 22/3389/…, or generic probe), each with a recommended action.\n3. MCP `top_talkers` and `states_table` → cross-check whether the source also has\n   *established* states, i.e. whether anything already got through.\n4. MCP `list_aliases` → find your blocklist alias, then `alias_entries(<alias>)` to see\n   what is already in it.\n5. MCP `add_alias_entry(alias=<blocklist>, entry=<src-ip>)` → medium risk, reversible,\n   undo descriptor recorded from the fetched before-state.\n6. MCP `apply_changes` (high risk, audited) to make the alias live, then\n   `kill_states(source=<src-ip>)` to tear down any states the attacker already holds.\n7. **Failure branch**: if you blocked too wide a range and locked out legitimate traffic,\n   MCP `remove_alias_entry` (or `firewall-aiops undo apply <id>`) and `apply_changes`\n   again. If you locked *yourself* out of the web UI, the CLI still works over the API\n   as long as the management rule was untouched — recover there before rebooting.\n\n### 4. Verify and roll back a change window\n\n1. Before the window: `firewall-aiops overview` and `firewall-aiops rules list` → capture\n   the baseline you intend to return to.\n2. Make the staged changes (`rules toggle`, MCP alias edits), each one dry-run first.\n3. MCP `apply_changes` with `FIREWALL_AUDIT_APPROVED_BY` set → commit.\n4. Validate: `firewall-aiops overview`, MCP `gateway_health_rca`, and\n   `firewall-aiops log --action block --limit 50` → make sure the change did not start\n   silently dropping wanted traffic.\n5. `firewall-aiops undo list` → every reversible write in the window, newest first, with\n   its `_undo_id`.\n6. **Failure branch**: roll the window back in reverse order with\n   `firewall-aiops undo apply <id>` per entry, then one final `apply_changes` to commit\n   the rollback. Writes that declare **no** undo (`reboot`, and `apply_changes` itself)\n   cannot be reversed this way — they are audit-only, which is why every reversible edit\n   goes in *before* the commit.\n\n> **Authorization is not this skill's job**: there is no read-only switch, policy\n> file, or approval gate. Whether a write runs is the agent's judgement or the\n> connecting account's permissions — point the tool at an API user without write\n> scope and writes fail at the server. Every call is still audited.\n> `FIREWALL_AUDIT_APPROVED_BY` / `FIREWALL_AUDIT_RATIONALE` are optional audit\n> annotations, recorded when set but never required.\n\n## Governance & Safety\n\n- Every tool is audited to `~/.firewall-aiops/audit.db` (relocatable via\n  `FIREWALL_AIOPS_HOME`).\n- High-risk ops (`apply_changes`, `reconfigure`, `reboot`) are labelled risk=high\n  and audited; `FIREWALL_AUDIT_APPROVED_BY` / `FIREWALL_AUDIT_RATIONALE` are\n  optional audit annotations, recorded when set but never required.\n- Writes support `--dry-run` and double confirmation at the CLI. `reboot` is\n  irreversible (audit only).\n- Reversible writes capture the real fetched before-state and record an inverse\n  descriptor (toggle→toggle-back, add-alias↔remove-alias).\n\n## References\n\n- `references/capabilities.md` — full tool + platform + API-path reference\n- `references/cli-reference.md` — CLI command reference\n- `references/setup-guide.md` — onboarding, credentials, and connectivity\n- `docs/VERIFICATION.md` — live-verification checklist (what the mock suite covers, and what a real-firewall run must prove)\n\nFile v0.12.4:_meta.json\n\n{\n  \"ownerId\": \"kn7b067awq2s97bn3d7p5qfhw5827pxc\",\n  \"slug\": \"firewall-aiops\",\n  \"version\": \"0.12.4\",\n  \"publishedAt\": 1789451887759\n}\n\nFile v0.12.4:references/agent-guardrails.md\n\n# Agent guardrails — running firewall-aiops with a smaller / local model\n\nIf you drive these tools with a local model (Llama, Qwen, Mistral … via Goose,\nOllama, LM Studio, or any OpenAI-compatible runtime), you will get noticeably\nbetter results with a short system prompt. This page gives you one, and — more\nimportantly — tells you which guardrails you **no longer need to write**, because\nthe tool now enforces them itself.\n\nThe distinction matters. A guardrail in a prompt is a request. A guardrail in the\nharness is a guarantee. Anything below that we could move into the harness, we did.\n\n## Authorization is not this tool's job — decide it where it belongs\n\nWhether a write should happen is your decision, or the account's. The tool does\nnot gate it — there is no read-only switch and no approval prompt to configure.\nThe two right places to control read vs write:\n\n- **The account you connect with.** Give the OPNsense/pfSense API user a\n  read-only role. A write then fails at the server, which is the only place the\n  permission actually lives — no skill-side flag can be argued around by a model,\n  but a revoked permission cannot be.\n- **Your agent's system prompt.** If you want an observe-only session, tell the\n  model not to call the write tools (they are clearly tagged `[WRITE]`).\n\nWhat the tool *does* guarantee is that you can always see what happened:\n\n## What the tool now enforces — do not waste prompt budget on these\n\n| You might be tempted to prompt | Why you don't need to |\n|---|---|\n| \"Never restart the web GUI / lock yourself out\" | **Already enforced.** `restart_service` refuses the daemon serving this appliance's own API (`nginx`, `lighttpd`, `configd`, `webgui`, ...), and `apply_changes` / `reconfigure` refuse a staged rule set that would provably cut management access. Both are exact and fail open — see `capabilities.md`. Do not spend prompt budget on it. |\n| \"Don't invent a value when a field is missing\" | OPNsense and pfSense populate different keys for the same concept. A field neither platform returned comes back as `null`, never as `\"\"`. Absent and empty are distinguishable in the payload. |\n| \"Tell me if the output was cut off\" | `firewall_log`, `states_table` and `top_talkers` return `{\"entries\": [...], \"returned\": N, \"limit\": L, \"truncated\": true/false}`. Truncation is measured, not guessed from a length coincidence. |\n| \"Preserve the ordering / tell me what's most urgent\" | The RCA tools (`gateway_health_rca`, `rule_hit_and_shadow_analysis`, `blocked_traffic_rca`) return findings with the measured numbers attached, worst-first. Priority is in the payload, not implied by list position. |\n| \"Confirm before anything destructive\" | Write operations require a `--dry-run`-able preview plus double confirmation at the CLI. |\n| \"Log what you did\" | Every governed call is audited to `~/.firewall-aiops/audit.db` regardless of what the model says it did. |\n\n## What still needs a prompt\n\nThese are model-behaviour problems the harness cannot fix from the outside.\nCopy this into your agent's system prompt:\n\n```text\nYou operate an OPNsense or pfSense firewall through the firewall-aiops MCP tools.\n\nTOOL USE\n- Before answering any question about the current firewall, you MUST call a\n  tool. Never answer from memory or assumption.\n- Actually invoke the tool. Do not describe the call you would make, and do not\n  emit an example JSON response in place of calling it.\n- If a tool call fails, report the real error verbatim. Never fill the gap with\n  a plausible-sounding answer.\n\nREADING RESULTS\n- Read the whole result before concluding. If a result contains a \"truncated\"\n  field that is true, say so and re-run with a higher limit instead of treating\n  the partial result as complete.\n- A null field means neither platform returned that value. Report it as \"not\n  available\" — never infer it. In particular, a rule with a null \"interface\" is\n  not a rule on an interface named \"none\".\n- Report values exactly as returned. Do not normalise, translate, or prettify\n  rule actions, gateway statuses, or interface names.\n- A gateway whose status is \"none\" is unmonitored, not down. A gateway with no\n  status field at all is unknown — say so rather than calling it healthy.\n\nSCOPE\n- Separate observation from interpretation. State what the tools returned, then\n  any interpretation, clearly marked as such.\n- Do not assert that traffic is being blocked by a specific rule unless a log\n  entry or the shadow analysis actually names that rule.\n- Do not add generic firewall advice that does not follow from the tool output.\n- Do not confuse a rule UUID with an alias name, an interface name (wan, lan,\n  opt1) with its description, or a gateway name with its monitor IP.\n- OPNsense and pfSense are different platforms with different API shapes. Do not\n  suggest an OPNsense-only action on a pfSense target; the target's platform is\n  reported in the overview.\n\nCHANGES ARE TWO-STEP\n- On OPNsense, editing a rule stages it; nothing takes effect until\n  apply_changes is called. Never report a change as live before that.\n```\n\n## Recommended setup for a local model\n\nStart with a connection that *cannot* write, verify, and widen the account's\npermission only when you trust the setup. A read-only role is a sensible default\nfor a firewall specifically: a mistaken `toggle_rule` or `reboot` on the box that\ncarries your management session locks you out of the thing you were trying to fix.\n\n```bash\n# Give the OPNsense/pfSense API user a read-only role, then:\nfirewall-aiops doctor\n```\n\nOptionally annotate the audit trail with who is operating and why — recorded on\nevery row, never required:\n\n```bash\nexport FIREWALL_AUDIT_APPROVED_BY=\"your.name@example.com\"\nexport FIREWALL_AUDIT_RATIONALE=\"scheduled maintenance window 2026-07-20\"\n```\n\n## If your model still struggles\n\nSome behaviours are model-capacity limits rather than prompt problems:\n\n- **Multi-tool workflows time out or drift.** Prefer the RCA tools\n  (`gateway_health_rca`, `blocked_traffic_rca`,\n  `rule_hit_and_shadow_analysis`) — they do the multi-step correlation inside\n  one call, so the model does not have to chain reads and keep rule UUIDs\n  straight.\n- **The model ignores later tool results in a long context.** The firewall log\n  and state table are the two big payloads here; ask narrower questions and use\n  `--limit` / `top` deliberately rather than pulling the whole state table.\n- **The model describes calls instead of making them.** This is usually a\n  runtime/tool-calling-format mismatch, not a prompt problem — check that your\n  client advertises the tools in the format your model was trained on.\n\nFeedback on running this with a specific local model is genuinely useful —\nopen an issue at\n[github.com/AIops-tools/Firewall-AIops](https://github.com/AIops-tools/Firewall-AIops/issues)\nwith the model, runtime, and what went wrong.\n\nFile v0.12.4:references/capabilities.md\n\n# firewall-aiops capabilities\n\n> **35 MCP tools** (26 read, 9 write) across OPNsense (REST `/api/...`, API key+secret\n> via HTTP Basic) and pfSense (REST v2 `/api/v2/...`, API key via `X-API-Key`). The\n> concrete REST paths below are modelled from each project's public API and have not\n> yet been exercised against a live firewall — see `docs/VERIFICATION.md`.\n\nA per-target `platform` field (`opnsense` / `pfsense`) selects the API shape; the same\ntool name resolves to the right path on each firewall via the platform registry.\n\n## System (read)\n\n| Tool | OPNsense path | pfSense path | Returns |\n|------|---------------|--------------|---------|\n| `firmware_status` | `/api/core/firmware/status` | `/api/v2/system/version` | version, product, updates available |\n| `health_status` | `/api/diagnostics/system/systemInformation` | `/api/v2/status/system` | hostname, uptime, CPU %, mem %, load |\n| `interface_status` | `/api/diagnostics/interface/getInterfaceNames` | `/api/v2/status/interfaces` | interfaces with link status + address (down first) |\n| `gateway_status` | `/api/routes/gateway/status` | `/api/v2/status/gateways` | gateways with status, loss %, RTT |\n\n## Rules (read)\n\n| Tool | OPNsense path | pfSense path | Returns |\n|------|---------------|--------------|---------|\n| `list_rules` | `/api/firewall/filter/searchRule` | `/api/v2/firewall/rules` | filter rules normalized (uuid, enabled, action, if, src/dst, evaluations) |\n| `rule_detail` | `/api/firewall/filter/getRule/{uuid}` | `/api/v2/firewall/rule?id=` | one rule's full detail |\n| `rule_stats` | `/api/diagnostics/firewall/pfStatistics` | `/api/v2/firewall/rules` | per-rule hit counts / evaluations, busiest first |\n| `rule_states` | `/api/diagnostics/firewall/queryStates` | `/api/v2/firewall/states` | active state-table entries tied to rules |\n| `pending_changes` | (derived from `searchRule`) | (derived from `firewall/rules`) | the staged rule set `apply_changes` would commit + its lockout assessment |\n\n## NAT (read)\n\n| Tool | Returns |\n|------|---------|\n| `nat_port_forwards` | inbound port-forward (DNAT) rules |\n| `nat_outbound` | outbound (source) NAT mappings |\n| `nat_one_to_one` | 1:1 NAT mappings (external ↔ internal) |\n\n## Aliases (read)\n\n| Tool | Returns |\n|------|---------|\n| `list_aliases` | all aliases (name, type, description, member count) |\n| `alias_entries` | the member entries (hosts/networks/ports) of one alias |\n\n## VPN (read)\n\n| Tool | Returns |\n|------|---------|\n| `wireguard_status` | WireGuard peers with connected state, last handshake, transfer |\n| `openvpn_sessions` | OpenVPN sessions / connected clients (name, address, bytes) |\n| `ipsec_sas` | IPsec security associations (phase-1/phase-2) with state |\n\n## DHCP (read)\n\n| Tool | Returns |\n|------|---------|\n| `dhcp_leases` | active DHCP leases (IP, MAC, hostname, state); `online_only` filter |\n| `dhcp_static_mappings` | DHCP static (reserved) mappings (MAC ↔ IP) |\n\n## Diagnostics (read)\n\n| Tool | Returns |\n|------|---------|\n| `firewall_log` | recent firewall-log entries, optional `action` filter (pass/block/…) |\n| `states_table` | active pf state-table entries |\n| `top_talkers` | busiest source hosts, aggregated from the state table by bytes |\n\n## Flagship analyses (read, pure heuristics)\n\n| Tool | What it does |\n|------|--------------|\n| `gateway_health_rca` | rank gateways by loss (x10) + latency; flag down (status down / 100% loss) and degraded (over threshold); map each to a cause + action. Pass `gateways=` for pure analysis or a target to pull live |\n| `rule_hit_and_shadow_analysis` | never-hit enabled rules (0 evaluations), rules shadowed by an earlier terminating rule, and exact duplicates; each finding names the offending/covering rule uuid |\n| `blocked_traffic_rca` | aggregate blocked log rows by source; classify as port scan (≥10 distinct ports), service brute-force/probe (busy sensitive port 22/3389/…), or generic; with an action |\n\n## Writes (governed)\n\n| Tool | Risk | Path(s) | Notes |\n|------|------|---------|-------|\n| `toggle_rule` | **med** | OPNsense `toggleRule/{uuid}/{0\\|1}`; pfSense PATCH `firewall/rule` | reads the rule first; records undo (restore prior enabled). Staged — run `apply_changes` |\n| `add_alias_entry` | **med** | OPNsense `alias_util/add/{name}`; pfSense `firewall/alias` | captures prior entries; undo removes the added entry |\n| `remove_alias_entry` | **med** | OPNsense `alias_util/delete/{name}`; pfSense `firewall/alias` | captures prior entries; undo adds it back |\n| `kill_states` | **med** | `diagnostics/…/killStates` / `firewall/states` (DELETE, query-filtered) | flush pf states (optionally one source IP) |\n| `restart_service` | **med** | `service/restart/{service}` | restart a firewall service; **refuses** the daemon serving this appliance's own API |\n| `apply_changes` | **HIGH** | `filter/apply` / `firewall/apply` | commit staged config — makes edits live; `dry_run` returns the staged set; **refuses** a provable lockout (`override=True` to force); audited |\n| `reconfigure` | **HIGH** | `filter/savepoint` / `firewall/apply` | reload/commit a subsystem; `dry_run` + audited |\n| `reboot` | **HIGH** | `core/system/reboot` / `diagnostics/reboot` | IRREVERSIBLE — audit only, no undo; `dry_run` |\n\n## Out of scope (v0.1)\n\n- Creating/deleting rules, aliases, or NAT entries from scratch (only toggle + alias\n  entry add/remove today).\n- Cloud security groups and vendor firewall appliances.\n- **Missing something? Open an issue or PR** — contributions welcome.\n\n## Self-lockout guards\n\nA firewall is the one appliance where a routine write severs the connection\ncarrying it — and the recorded undo needs that same connection. Three writes\nrefuse rather than let that happen. All of them are **exact** and **fail open**.\n\n### `restart_service`\n\nRefuses the daemon that answers this platform's own management API — OPNsense\n`nginx` / `configd` / `php-fpm`, pfSense `lighttpd` / `php-fpm`, plus the\ngeneric aliases (`webgui`, `web`, `webserver`, `gui`, `api`) an agent told\n\"restart the web service\" would actually pass. The list lives on the `Platform`\ndescriptor, which already knows which daemon serves its own URLs. Matching is\nexact and case-insensitive; an unrecognised service name is never blocked on a\nguess, so `unbound`, `dhcpd`, `openvpn`, `ipsec` and friends restart normally.\n\n### `apply_changes` / `reconfigure filter`\n\nBoth read the staged rule set first (see `pending_changes`) and refuse when\ncommitting it would provably cut management access. Two mirror-image shapes are\ndangerous:\n\n- a **disabled `pass`** rule that permits management access — applying removes the permit;\n- an **enabled `block`** rule that covers it — applying starts blocking.\n\n\"Provably\" means a literal match on **both** the management host and port.\nEverything short of that fails open with a named warning and proceeds:\n\n| Warning | Meaning |\n|---|---|\n| `ALIAS_DESTINATION` | destination is an alias; it may resolve to the management address |\n| `ANY_DESTINATION` | destination is `any` / a CIDR that may contain the host |\n| `ANY_PORT` | no destination port — may include the management port |\n| `PORT_RANGE` | port expression could not be parsed to a range |\n| `INTERFACE_GROUP` | rule is on `any` / an interface group |\n\n`override=True` proceeds despite a certain finding — for operators with console\naccess who mean it. A rule set that cannot be READ does not block either, but is\nreported as `assessed: false` with the error rather than as a clean bill of\nhealth (a failed probe is not \"nothing pending\").\n\n### `toggle_rule`\n\nRuns the same assessment at staging time — the cheapest point to warn, since the\nrule row is already in hand — and reports `managementImpact` in both directions.\nAdvisory only: staging is never blocked, because `apply_changes` is where the\nchange becomes real and where the refusal lives.\n\n### `dry_run` does not bypass the guards\n\nA `dry_run` whose honest answer is \"this would be refused\" **refuses**. Previewing\nsuccess for a call that is then refused is the preview being wrong, and a weak\nmodel reads the later refusal as transient and retries it. So:\n\n- `apply_changes(dry_run=True)` / `reconfigure(subsystem=\"filter\", dry_run=True)`\n  run the lockout guard before returning, and honour `override=True` on both paths.\n- `restart_service(dry_run=True)` refuses an API-serving service name.\n\n- `toggle_rule(dry_run=True)` reads the rule and reports the same\n  `managementImpact` the real call would.\n\nFail-open semantics are **identical** on both paths — a dry-run never refuses\nwhat the real call would allow.\n\nThe CLI's `rules toggle --dry-run` routes through the governed twin, so it\nreaches the same assessment **and** records the same audit row. The line's\ninvariant is: **a dry_run MAY read; it must never write.** A preview that cannot\nread cannot answer \"would this be refused?\", so reads are expected; the mutating\nPOST/PATCH is the thing that must never happen. (`apply_changes`,\n`reconfigure`, `restart_service`, `kill_states` and `reboot` have no CLI command\n— they are MCP-only — so `rules toggle` is the whole CLI write surface.)\n\n### Two pfSense reads depend on the pfSense-pkg-RESTAPI version\n\n`wireguard_status` and `dhcp_static_mappings` read endpoints that newer\npfSense-pkg-RESTAPI builds serve and older ones do not (`/api/v2/status/wireguard/peers`,\n`/api/v2/services/dhcp_server/static_mappings`). On a build that predates them the\ncall returns a 404 error payload naming the exact path — it is not \"WireGuard is\nnot configured\". Upgrade the package on the firewall to get those surfaces.\nEverything else in this table was exercised against pfSense CE 2.7.2 with\npfSense-pkg-RESTAPI 2.4_3.\n\n### `kill_states` is a lost response, not a lockout\n\nFlushing the pf state table drops the state entry for this tool's own\nconnection, so the call can appear to fail even though the flush ran. Access is\nNOT lost: the permitting rule is untouched and the next call re-establishes\nstate. The dry-run says so in `sessionImpact`, and the result repeats it in\n`note`. **Do not retry blindly** — the flush is likely already done.\n\n### Reversible writes survive a lost response\n\n`toggle_rule`, `add_alias_entry` and `remove_alias_entry` stash their before-state\nvia `capture_prior_state()` immediately before the mutating request. If the\nresponse is lost, the harness records `status=unknown` (not a false `error`) and\ncan still record the inverse, flagged `effectVerified=false`. The irreversible\nwrites (`apply_changes`, `reconfigure`, `restart_service`, `kill_states`,\n`reboot`) declare no inverse, so they capture nothing — there is nothing to\nreplay.\n\nFile v0.12.4:references/cli-reference.md\n\n# firewall-aiops CLI reference\n\n> Covers OPNsense (REST `/api/...`) and pfSense (REST v2 `/api/v2/...`). Responses are\n> validated against mocks; see `docs/VERIFICATION.md` for the live-run checklist.\n\n## Setup & diagnostics\n\n```bash\nfirewall-aiops init                      # interactive wizard (asks for the platform: opnsense/pfsense)\nfirewall-aiops doctor                    # check config, secrets, connectivity\n                                         #   firmware/version query on both platforms\nfirewall-aiops doctor --skip-auth        # config/secret checks only (no network)\nfirewall-aiops mcp                       # start the MCP server (stdio)\n```\n\n## Secrets (encrypted store)\n\n```bash\nfirewall-aiops secret set <target> [--value <secret>]  # store OPNsense secret / pfSense key (hidden prompt if no --value)\nfirewall-aiops secret list                             # list target names with a stored secret (values never shown)\nfirewall-aiops secret rm <target>                      # delete a stored secret\nfirewall-aiops secret migrate                          # import legacy plaintext .env into the encrypted store\nfirewall-aiops secret rotate-password                  # re-encrypt under a new master password\n```\n\n## Overview & rules\n\n```bash\nfirewall-aiops overview                        # one-shot: version + gateway/interface health + rule count\nfirewall-aiops rules list [--interface wan]    # list filter rules (optionally on one interface)\nfirewall-aiops rules show <uuid>               # one rule's full detail\nfirewall-aiops rules toggle <uuid> --disable   # governed write: dry-run + double-confirm\nfirewall-aiops rules toggle <uuid> --enable --dry-run\n```\n\n## Firewall log\n\n```bash\nfirewall-aiops log                             # recent firewall-log entries\nfirewall-aiops log --action block --limit 50   # only blocked traffic\n```\n\n## Notes\n\n- `--target/-t` selects a named target from `config.yaml`; omit for the default (first).\n- `overview`, `rules`, and `log` are the CLI subset; the full read surface (NAT,\n  aliases, VPN, DHCP, diagnostics), the three flagship analyses, and the remaining\n  governed writes (alias entry add/remove, kill_states, restart_service, apply_changes,\n  reconfigure, reboot) are exposed through the MCP server (`firewall-aiops mcp`).\n- High-risk writes (`apply_changes`, `reconfigure`, `reboot`) are labelled risk=high\n  and audited. `FIREWALL_AUDIT_APPROVED_BY` (and `FIREWALL_AUDIT_RATIONALE`) are\n  optional audit annotations, recorded when set but never required.\n\nFile v0.12.4:references/setup-guide.md\n\n# firewall-aiops setup & security guide\n\n> Both **OPNsense** (fully open-source) and **pfSense CE** (free) are self-hostable, so\n> a home lab is the easiest place to run the live checklist in `docs/VERIFICATION.md`.\n> The modelled REST paths are the largest verification debt.\n\n## 1. Install\n\n```bash\nuv tool install firewall-aiops       # or: pipx install firewall-aiops\n```\n\n## 2. What you need per firewall\n\n- **OPNsense** — an **API key + secret** pair (System → Access → Users → edit a user →\n  API keys → create). firewall-aiops talks to the REST API on port **443** and presents\n  the key+secret as HTTP Basic auth. Enable the OPNsense web GUI / API for the account.\n- **pfSense** — the **REST API v2** package (pfSense-pkg-RESTAPI) installed and an **API\n  key** issued by it. The API is under `/api/v2/...` on port **443**; the key is sent in\n  an `X-API-Key` header.\n\n## 3. Onboard with the wizard\n\n```bash\nfirewall-aiops init\n```\n\nThe wizard asks, per target, for the **platform** (`opnsense` / `pfsense`), the\n**host**, the **port** (default 443), the **OPNsense API key** (OPNsense only, saved as\n`username`), and the **secret** — the OPNsense API secret or the pfSense API key.\nNon-secret connection details go to `~/.firewall-aiops/config.yaml`; the secret is\nstored **encrypted** in `~/.firewall-aiops/secrets.enc`.\n\nExample `config.yaml`:\n\n```yaml\ntargets:\n  - name: fw1\n    platform: opnsense\n    host: 192.0.2.1\n    port: 443\n    username: <opnsense-api-key>\n    verify_ssl: true      # the default; set false ONLY for self-signed lab certs\n  - name: edge\n    platform: pfsense\n    host: 192.0.2.2\n    port: 443\n    verify_ssl: true\n    # scheme: http        # https is the default; set http ONLY when the GUI is\n    #                     # published over plain HTTP behind a proxy terminating TLS\n```\n\n## 4. Master password (for non-interactive / MCP use)\n\nThe encrypted store is unlocked by a master password. For the MCP server, CI, or cron,\nexport it so no prompt is needed:\n\n```bash\nexport FIREWALL_AIOPS_MASTER_PASSWORD='...'\n```\n\nOn a TTY the CLI prompts interactively if the env var is unset.\n\n## 5. Verify connectivity\n\n```bash\nfirewall-aiops doctor\n```\n\n`doctor` checks the config file, the encrypted store and its permissions, that each\ntarget has a secret, and (unless `--skip-auth`) live connectivity — a firmware/version\nquery on both platforms.\n\n## Security notes\n\n- The secret (OPNsense API secret / pfSense API key) is **never** written to disk in\n  plaintext — only the scrypt salt and Fernet ciphertext are stored (chmod 600). The\n  master password is never stored.\n- A legacy plaintext env var `FIREWALL_<TARGET_NAME_UPPER>_SECRET` is honoured as a\n  fallback with a deprecation warning (migrate with `firewall-aiops secret migrate`).\n- The secret is presented as HTTP Basic auth (OPNsense) or an `X-API-Key` header\n  (pfSense) at request time and held only in memory; secrets are never logged or echoed.\n- `verify_ssl` defaults to true; set `false` only for self-signed lab certificates.\n- `scheme` defaults to `https`; set `http` only when the GUI is published over plain\n  HTTP behind a proxy that terminates TLS for it.\n- Every MCP tool is audited to `~/.firewall-aiops/audit.db` (relocatable via\n  `FIREWALL_AIOPS_HOME`). High-risk writes (`apply_changes`, `reconfigure`, `reboot`)\n  are labelled risk=high and audited; `FIREWALL_AUDIT_APPROVED_BY` +\n  `FIREWALL_AUDIT_RATIONALE` are optional audit annotations, recorded when set but\n  never required.\n- No webhooks, no telemetry, no outbound calls beyond the configured OPNsense / pfSense\n  REST API. No post-install scripts or background services.\n\nFile v0.12.4:skill-card.md\n\n## Description:\n\nProvides governed OPNsense and pfSense firewall operations for health checks, rules, NAT, aliases, VPN, DHCP, logs, state tables, root-cause analyses, and audited firewall changes.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[zw008](https://clawhub.ai/user/zw008)\n\n### License/Terms of Use:\n\nMIT\n\n## Use Case:\n\nDevelopers, operators, and network administrators use this skill to inspect and operate OPNsense or pfSense firewalls through CLI and MCP workflows. It supports read-only diagnosis as well as governed write operations such as rule toggles, alias edits, service restarts, applying staged changes, and rebooting.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: High-impact firewall changes can affect access or availability.\n\nMitigation: Use dry runs first, operate during approved maintenance windows, keep console or alternate access available for high-risk changes, and use the skill's undo flow for reversible edits before applying staged changes.\n\nRisk: External package provenance is not server-resolved for this version.\n\nMitigation: Install only a pinned, reviewed release and validate the package source before connecting it to production firewalls.\n\nRisk: Weak approval and TLS safeguards can increase operational exposure.\n\nMitigation: Use a dedicated least-privilege API account, prefer read-only credentials by default, require HTTPS certificate verification or a private CA, and avoid the legacy plaintext secret fallback.\n\n## Reference(s):\n\n- [Firewall AIops homepage](https://github.com/AIops-tools/Firewall-AIops)\n- [Capabilities reference](references/capabilities.md)\n- [CLI reference](references/cli-reference.md)\n- [Setup and security guide](references/setup-guide.md)\n- [Agent guardrails](references/agent-guardrails.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown with inline shell commands and structured operational guidance]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May include firewall observations, RCA summaries, dry-run guidance, audit context, and rollback steps depending on the requested workflow.]\n\n## Skill Version(s):\n\n0.12.4 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.12.3: 7 files, 19984 bytes\n\nFiles: references/agent-guardrails.md (6900b), references/capabilities.md (10693b), references/cli-reference.md (2530b), references/setup-guide.md (3664b), skill-card.md (2592b), SKILL.md (16120b), _meta.json (134b)\n\nFile v0.12.3:SKILL.md\n\n---\nname: firewall-aiops\nslug: firewall-aiops\ndisplayName: \"Firewall AIops\"\nsummary: \"Governed OPNsense + pfSense firewall ops: rules, NAT, VPN, DHCP, RCA. 35 tools.\"\nlicense: MIT\nhomepage: https://github.com/AIops-tools/Firewall-AIops\ntags: [aiops, mcp, governance, firewall]\ndescription: >\n  Use this skill whenever the user needs to operate an OPNsense or pfSense firewall — a one-shot overview, firmware/health, interfaces and gateways, firewall rules with hit-counts and shadow analysis, NAT (port-forward/outbound/1:1), aliases and their entries, VPN (WireGuard/OpenVPN/IPsec), DHCP leases and static mappings, the firewall log and state table, three flagship RCAs (gateway health, rule hit/shadow, blocked traffic), and governed writes (toggle a rule, add/remove an alias entry, kill states, restart a service, apply/reconfigure to make edits live, reboot).\n  Always use this skill for \"OPNsense\", \"pfSense\", \"firewall rule\", \"port forward\", \"NAT\", \"alias\", \"WireGuard\", \"OpenVPN\", \"IPsec\", \"DHCP lease\", \"firewall log\", \"blocked traffic\", \"why is my WAN down\", \"gateway loss/latency\", \"unused / shadowed rules\", \"apply firewall changes\", \"reboot the firewall\" when the context is an OPNsense/pfSense firewall.\n  Do NOT use when the target is something other than an OPNsense/pfSense firewall (a hypervisor, storage appliance, backup product, container-orchestration cluster, multi-vendor router/switch config, or OT/industrial equipment) — route those to the appropriate other AIops-tools skill. Cloud security groups and vendor firewall appliances are out of scope.\n  Governed firewall operations with a built-in governance harness (audit, policy, token budget, undo, risk-tiers). Live-verified against real OPNsense 26.7 and pfSense CE 2.7.2 on top of the mock test suite; see docs/VERIFICATION.md for exactly what each run proved and what is still untested.\ninstaller:\n  kind: uv\n  package: firewall-aiops\nargument-hint: \"[a rule/alias id, an IP, or describe your firewall task]\"\nallowed-tools:\n  - Bash\nmetadata: {\"openclaw\":{\"requires\":{\"anyBins\":[\"firewall-aiops\",\"uvx\"]},\"optional\":{\"env\":[\"FIREWALL_AIOPS_CONFIG\",\"FIREWALL_AIOPS_MASTER_PASSWORD\"]},\"homepage\":\"https://github.com/AIops-tools/Firewall-AIops\",\"emoji\":\"🛡️\",\"os\":[\"macos\",\"linux\"]}}\ncompatibility: >\n  Standalone, self-governed firewall operations across OPNsense (REST API /api/..., API key+secret via HTTP Basic auth) and pfSense (REST API v2 /api/v2/..., API key via X-API-Key header). Each target in the config names its own platform, and a name-keyed platform registry selects the API shape, so the same tools work on both and one config can span a mixed estate. The governance harness (audit, policy, token/runaway budget, undo, risk-tiers) is bundled in the package — no external skill-family dependency.\n  All write operations are audited to a local SQLite DB under ~/.firewall-aiops/ (relocatable via FIREWALL_AIOPS_HOME).\n  Credentials: the OPNsense API secret (paired with the API key) or the pfSense API key is stored ENCRYPTED in ~/.firewall-aiops/secrets.enc (Fernet/AES-128 + scrypt-derived key) — never plaintext on disk. Run 'firewall-aiops init' to onboard (it asks for the platform), or 'firewall-aiops secret set <target>' to add one. The store is unlocked by a master password from FIREWALL_AIOPS_MASTER_PASSWORD (non-interactive/MCP/CI) or an interactive prompt (CLI on a TTY). A legacy plaintext env var FIREWALL_<TARGET_NAME_UPPER>_SECRET is still honoured as a fallback with a deprecation warning (migrate with 'firewall-aiops secret migrate'). The secret is presented as HTTP Basic auth (OPNsense) or an X-API-Key header (pfSense) at request time and held only in memory; secrets are never logged or echoed.\n  State-changing operations pass through the @governed_tool decorator (budget guard + audit + a descriptive risk-tier label, not a gate). The high-risk commits (apply_changes, reconfigure) and reboot are risk=high with dry_run; reboot is irreversible. Reversible writes (toggle_rule, add_alias_entry, remove_alias_entry) capture the real fetched before-state and record an inverse undo descriptor. Three writes additionally refuse to destroy the tool's own management path: restart_service refuses the daemon serving this appliance's API, and apply_changes / reconfigure refuse a staged rule set that would provably cut management access.\n  Webhooks: none — no outbound network calls beyond the configured OPNsense / pfSense REST API.\n  SSL: verify_ssl defaults to false-friendly for self-signed lab certs; enable for production.\n  Transitive dependencies: httpx (HTTP client) and the MCP SDK. No post-install scripts or background services.\n---\n\n# Firewall AIops\n\n> **Disclaimer**: Community-maintained open-source project, **not affiliated with, endorsed by, or sponsored by the OPNsense project, Deciso, Netgate, or the pfSense project.** OPNsense, pfSense and Netgate are trademarks of their respective owners. Source at [github.com/AIops-tools/Firewall-AIops](https://github.com/AIops-tools/Firewall-AIops) under the MIT license.\n\nGoverned firewall operations — **35 MCP tools** across **OPNsense** (REST `/api/...`)\nand **pfSense** (REST v2 `/api/v2/...`), every one wrapped with the bundled\n`@governed_tool` harness: a local unified audit log under `~/.firewall-aiops/`,\npolicy engine, token/runaway budget guard, undo-token recording, and\ndescriptive risk-tier labelling. A per-target `platform` field selects the API shape,\nso the same tools work on both firewalls and one config can span a mixed estate. The\nOPNsense API secret / pfSense API key is stored **encrypted**\n(`~/.firewall-aiops/secrets.enc`, Fernet + scrypt) — never plaintext on disk.\n\n> **Standalone**: the governance harness is bundled in the package\n> (`firewall_aiops.governance`) — no external skill-family dependency. Both platform\n> halves have been exercised against real firewalls (OPNsense 26.7, pfSense CE 2.7.2)\n> in addition to the mock suite; `docs/VERIFICATION.md` records what each live run\n> proved, and what remains untested on each platform.\n\n## What This Skill Does\n\n| Group | Tools | Count | R/W |\n|-------|-------|:-----:|:---:|\n| **System** | firmware_status, health_status, interface_status, gateway_status | 4 | read |\n| **Rules** | list_rules, rule_detail, rule_stats, rule_states, pending_changes | 5 | read |\n| **NAT** | nat_port_forwards, nat_outbound, nat_one_to_one | 3 | read |\n| **Aliases** | list_aliases, alias_entries | 2 | read |\n| **VPN** | wireguard_status, openvpn_sessions, ipsec_sas | 3 | read |\n| **DHCP** | dhcp_leases, dhcp_static_mappings | 2 | read |\n| **Diagnostics** | firewall_log, states_table, top_talkers | 3 | read |\n| **Flagship analyses** | gateway_health_rca, rule_hit_and_shadow_analysis, blocked_traffic_rca | 3 | read |\n| **Writes** | toggle_rule, add_alias_entry, remove_alias_entry, kill_states, restart_service | 5 | write (med) |\n| **Writes** | apply_changes, reconfigure, reboot | 3 | write (**high**) |\n| **Undo** | undo_list, undo_apply | 2 | read / write |\n\nThe three flagship analyses are transparent heuristics that report their numbers,\nnever a black-box verdict: `gateway_health_rca` ranks gateways by loss + latency and\nmaps each down/degraded one to a cause + action; `rule_hit_and_shadow_analysis` finds\nnever-hit and shadowed/redundant rules; `blocked_traffic_rca` classifies the noisiest\nblocked sources as scan / brute-force / probe.\n\n## Quick Install\n\n```bash\nuv tool install firewall-aiops\nfirewall-aiops init       # wizard: pick platform (opnsense/pfsense) + encrypted secret\nfirewall-aiops doctor\n```\n\nOr as an OpenClaw plugin, which installs this skill and its MCP server together:\n\n```bash\nopenclaw plugins install clawhub:@zw008/firewall-aiops\nopenclaw skills info firewall-aiops          # expect: Visible to model: yes\n```\n\nNeeds `uvx` on `PATH`: the MCP server is fetched with uv, pinned to this release.\n\n## When to Use This Skill\n\n- Get a one-shot snapshot (`overview` / `firmware_status` / `gateway_status`)\n- Investigate a down/degraded WAN (`gateway_health_rca`) → cause + action\n- Audit the ruleset (`rule_stats` hit counts, `rule_hit_and_shadow_analysis` for\n  never-hit / shadowed / redundant rules)\n- Triage hostile traffic (`firewall_log --action block`, `blocked_traffic_rca`,\n  `top_talkers`)\n- Inspect NAT, aliases, VPN tunnels (WireGuard/OpenVPN/IPsec), and DHCP leases\n- Safely toggle a rule or edit an alias (`toggle_rule` / `add_alias_entry` /\n  `remove_alias_entry`, reversible + undo-recorded), then **make it live** with\n  `apply_changes` (dry-run + audit)\n\n**Do NOT use when** the target is not an OPNsense/pfSense firewall — route hypervisor,\nstorage, backup, cluster, multi-vendor router/switch config, or OT/industrial work to\nthe appropriate other AIops-tools skill.\n\n## Related Skills — Skill Routing\n\n| If the user wants… | Use |\n|--------------------|-----|\n| OPNsense / pfSense firewall ops | **firewall-aiops** (this skill) |\n| A non-firewall platform (hypervisor, storage, backup, cluster, network config, OT edge) | the appropriate **other AIops-tools** skill |\n| Cloud security groups / vendor firewall appliances | out of scope for this tool |\n\n## Common Workflows\n\nThe CLI surface is `init` / `doctor` / `overview` / `log` / `rules` / `secret` / `undo`;\nthe flagship RCAs, NAT / alias / VPN / DHCP reads, and the remaining governed writes are\nMCP tools (start the server with `firewall-aiops mcp`). Recipes below say which is which.\n\n### 1. \"The internet keeps dropping\" — WAN gateway triage\n\n1. `firewall-aiops doctor` → confirm the firewall is reachable and the secret unlocks\n   (a red doctor means you are debugging credentials, not the WAN).\n2. `firewall-aiops overview` → one-shot: firmware/version, gateway + interface health,\n   rule count. Down interfaces sort first.\n3. MCP `gateway_health_rca` → gateways ranked worst-first, each row citing its measured\n   loss % and RTT, mapped to a cause (last-mile loss / congestion / latency / hard down)\n   and a concrete action.\n4. If the RCA points at a stuck daemon rather than the circuit, MCP\n   `restart_service(service=\"dpinger\", dry_run=true)` to preview, then re-run for real\n   (medium risk, audited, undo-recorded).\n5. Re-run `firewall-aiops overview` to confirm the gateway came back green.\n6. **Failure branch**: if the restart does not clear it, the gateway is genuinely down\n   upstream — stop touching the firewall and escalate to the ISP. If the restart made\n   things worse, `firewall-aiops undo list` → `firewall-aiops undo apply <id>` reverses\n   the recorded inverse. Do **not** reach for `reboot` (high risk, irreversible, no undo)\n   until a read confirms it is the only remaining option.\n\n### 2. Ruleset spring-clean — retire a rule that never fires\n\n1. MCP `rule_hit_and_shadow_analysis` → enabled rules with 0 evaluations (dead or\n   misordered), rules shadowed by an earlier terminating rule, and exact duplicates —\n   each finding names the offending and the covering rule uuid.\n2. `firewall-aiops rules list --interface wan` → confirm the candidate's position in the\n   evaluation order (a \"never hit\" rule below a broad allow is misordered, not useless).\n3. `firewall-aiops rules show <uuid>` → read the full rule before touching it.\n4. `firewall-aiops rules toggle <uuid> --disable --dry-run` → prints the exact call,\n   changes nothing.\n5. `firewall-aiops rules toggle <uuid> --disable` → double-confirm; the write fetches the\n   rule's real prior enabled flag and records an inverse undo descriptor with an `_undo_id`.\n6. MCP `pending_changes` → read what the commit would actually make live, including\n   whether any staged rule covers the endpoint this tool manages the firewall through.\n   `toggle_rule` already reported `managementImpact` in step 5 if so.\n7. MCP `apply_changes` to commit the staged config — **risk=high**, so set\n   `FIREWALL_AUDIT_APPROVED_BY` and `FIREWALL_AUDIT_RATIONALE` first. It refuses\n   outright if a staged rule would provably cut management access; pass\n   `override=True` only with console access in hand.\n8. **Failure branch**: if traffic breaks after the commit, `firewall-aiops undo apply <id>`\n   restores the rule's prior enabled state, then `apply_changes` again to make the\n   restoration live. The toggle is staged until applied — before step 6 you can simply\n   toggle it back with no commit at all.\n\n### 3. Brute-force against the WAN — block the source with an alias\n\n1. `firewall-aiops log --action block --limit 100` → the raw recent blocks, so you are\n   reading real log lines and not just a summary.\n2. MCP `blocked_traffic_rca` → noisiest blocked sources ranked and classified (port scan,\n   service brute-force on 22/3389/…, or generic probe), each with a recommended action.\n3. MCP `top_talkers` and `states_table` → cross-check whether the source also has\n   *established* states, i.e. whether anything already got through.\n4. MCP `list_aliases` → find your blocklist alias, then `alias_entries(<alias>)` to see\n   what is already in it.\n5. MCP `add_alias_entry(alias=<blocklist>, entry=<src-ip>)` → medium risk, reversible,\n   undo descriptor recorded from the fetched before-state.\n6. MCP `apply_changes` (high risk, audited) to make the alias live, then\n   `kill_states(source=<src-ip>)` to tear down any states the attacker already holds.\n7. **Failure branch**: if you blocked too wide a range and locked out legitimate traffic,\n   MCP `remove_alias_entry` (or `firewall-aiops undo apply <id>`) and `apply_changes`\n   again. If you locked *yourself* out of the web UI, the CLI still works over the API\n   as long as the management rule was untouched — recover there before rebooting.\n\n### 4. Verify and roll back a change window\n\n1. Before the window: `firewall-aiops overview` and `firewall-aiops rules list` → capture\n   the baseline you intend to return to.\n2. Make the staged changes (`rules toggle`, MCP alias edits), each one dry-run first.\n3. MCP `apply_changes` with `FIREWALL_AUDIT_APPROVED_BY` set → commit.\n4. Validate: `firewall-aiops overview`, MCP `gateway_health_rca`, and\n   `firewall-aiops log --action block --limit 50` → make sure the change did not start\n   silently dropping wanted traffic.\n5. `firewall-aiops undo list` → every reversible write in the window, newest first, with\n   its `_undo_id`.\n6. **Failure branch**: roll the window back in reverse order with\n   `firewall-aiops undo apply <id>` per entry, then one final `apply_changes` to commit\n   the rollback. Writes that declare **no** undo (`reboot`, and `apply_changes` itself)\n   cannot be reversed this way — they are audit-only, which is why every reversible edit\n   goes in *before* the commit.\n\n> **Authorization is not this skill's job**: there is no read-only switch, policy\n> file, or approval gate. Whether a write runs is the agent's judgement or the\n> connecting account's permissions — point the tool at an API user without write\n> scope and writes fail at the server. Every call is still audited.\n> `FIREWALL_AUDIT_APPROVED_BY` / `FIREWALL_AUDIT_RATIONALE` are optional audit\n> annotations, recorded when set but never required.\n\n## Governance & Safety\n\n- Every tool is audited to `~/.firewall-aiops/audit.db` (relocatable via\n  `FIREWALL_AIOPS_HOME`).\n- High-risk ops (`apply_changes`, `reconfigure`, `reboot`) are labelled risk=high\n  and audited; `FIREWALL_AUDIT_APPROVED_BY` / `FIREWALL_AUDIT_RATIONALE` are\n  optional audit annotations, recorded when set but never required.\n- Writes support `--dry-run` and double confirmation at the CLI. `reboot` is\n  irreversible (audit only).\n- Reversible writes capture the real fetched before-state and record an inverse\n  descriptor (toggle→toggle-back, add-alias↔remove-alias).\n\n## References\n\n- `references/capabilities.md` — full tool + platform + API-path reference\n- `references/cli-reference.md` — CLI command reference\n- `references/setup-guide.md` — onboarding, credentials, and connectivity\n- `docs/VERIFICATION.md` — live-verification checklist (what the mock suite covers, and what a real-firewall run must prove)\n\nFile v0.12.3:_meta.json\n\n{\n  \"ownerId\": \"kn7b067awq2s97bn3d7p5qfhw5827pxc\",\n  \"slug\": \"firewall-aiops\",\n  \"version\": \"0.12.3\",\n  \"publishedAt\": 1789256416038\n}\n\nFile v0.12.3:references/agent-guardrails.md\n\n# Agent guardrails — running firewall-aiops with a smaller / local model\n\nIf you drive these tools with a local model (Llama, Qwen, Mistral … via Goose,\nOllama, LM Studio, or any OpenAI-compatible runtime), you will get noticeably\nbetter results with a short system prompt. This page gives you one, and — more\nimportantly — tells you which guardrails you **no longer need to write**, because\nthe tool now enforces them itself.\n\nThe distinction matters. A guardrail in a prompt is a request. A guardrail in the\nharness is a guarantee. Anything below that we could move into the harness, we did.\n\n## Authorization is not this tool's job — decide it where it belongs\n\nWhether a write should happen is your decision, or the account's. The tool does\nnot gate it — there is no read-only switch and no approval prompt to configure.\nThe two right places to control read vs write:\n\n- **The account you connect with.** Give the OPNsense/pfSense API user a\n  read-only role. A write then fails at the server, which is the only place the\n  permission actually lives — no skill-side flag can be argued around by a model,\n  but a revoked permission cannot be.\n- **Your agent's system prompt.** If you want an observe-only session, tell the\n  model not to call the write tools (they are clearly tagged `[WRITE]`).\n\nWhat the tool *does* guarantee is that you can always see what happened:\n\n## What the tool now enforces — do not waste prompt budget on these\n\n| You might be tempted to prompt | Why you don't need to |\n|---|---|\n| \"Never restart the web GUI / lock yourself out\" | **Already enforced.** `restart_service` refuses the daemon serving this appliance's own API (`nginx`, `lighttpd`, `configd`, `webgui`, ...), and `apply_changes` / `reconfigure` refuse a staged rule set that would provably cut management access. Both are exact and fail open — see `capabilities.md`. Do not spend prompt budget on it. |\n| \"Don't invent a value when a field is missing\" | OPNsense and pfSense populate different keys for the same concept. A field neither platform returned comes back as `null`, never as `\"\"`. Absent and empty are distinguishable in the payload. |\n| \"Tell me if the output was cut off\" | `firewall_log`, `states_table` and `top_talkers` return `{\"entries\": [...], \"returned\": N, \"limit\": L, \"truncated\": true/false}`. Truncation is measured, not guessed from a length coincidence. |\n| \"Preserve the ordering / tell me what's most urgent\" | The RCA tools (`gateway_health_rca`, `rule_hit_and_shadow_analysis`, `blocked_traffic_rca`) return findings with the measured numbers attached, worst-first. Priority is in the payload, not implied by list position. |\n| \"Confirm before anything destructive\" | Write operations require a `--dry-run`-able preview plus double confirmation at the CLI. |\n| \"Log what you did\" | Every governed call is audited to `~/.firewall-aiops/audit.db` regardless of what the model says it did. |\n\n## What still needs a prompt\n\nThese are model-behaviour problems the harness cannot fix from the outside.\nCopy this into your agent's system prompt:\n\n```text\nYou operate an OPNsense or pfSense firewall through the firewall-aiops MCP tools.\n\nTOOL USE\n- Before answering any question about the current firewall, you MUST call a\n  tool. Never answer from memory or assumption.\n- Actually invoke the tool. Do not describe the call you would make, and do not\n  emit an example JSON response in place of calling it.\n- If a tool call fails, report the real error verbatim. Never fill the gap with\n  a plausible-sounding answer.\n\nREADING RESULTS\n- Read the whole result before concluding. If a result contains a \"truncated\"\n  field that is true, say so and re-run with a higher limit instead of treating\n  the partial result as complete.\n- A null field means neither platform returned that value. Report it as \"not\n  available\" — never infer it. In particular, a rule with a null \"interface\" is\n  not a rule on an interface named \"none\".\n- Report values exactly as returned. Do not normalise, translate, or prettify\n  rule actions, gateway statuses, or interface names.\n- A gateway whose status is \"none\" is unmonitored, not down. A gateway with no\n  status field at all is unknown — say so rather than calling it healthy.\n\nSCOPE\n- Separate observation from interpretation. State what the tools returned, then\n  any interpretation, clearly marked as such.\n- Do not assert that traffic is being blocked by a specific rule unless a log\n  entry or the shadow analysis actually names that rule.\n- Do not add generic firewall advice that does not follow from the tool output.\n- Do not confuse a rule UUID with an alias name, an interface name (wan, lan,\n  opt1) with its description, or a gateway name with its monitor IP.\n- OPNsense and pfSense are different platforms with different API shapes. Do not\n  suggest an OPNsense-only action on a pfSense target; the target's platform is\n  reported in the overview.\n\nCHANGES ARE TWO-STEP\n- On OPNsense, editing a rule stages it; nothing takes effect until\n  apply_changes is called. Never report a change as live before that.\n```\n\n## Recommended setup for a local model\n\nStart with a connection that *cannot* write, verify, and widen the account's\npermission only when you trust the setup. A read-only role is a sensible default\nfor a firewall specifically: a mistaken `toggle_rule` or `reboot` on the box that\ncarries your management session locks you out of the thing you were trying to fix.\n\n```bash\n# Give the OPNsense/pfSense API user a read-only role, then:\nfirewall-aiops doctor\n```\n\nOptionally annotate the audit trail with who is operating and why — recorded on\nevery row, never required:\n\n```bash\nexport FIREWALL_AUDIT_APPROVED_BY=\"your.name@example.com\"\nexport FIREWALL_AUDIT_RATIONALE=\"scheduled maintenance window 2026-07-20\"\n```\n\n## If your model still struggles\n\nSome behaviours are model-capacity limits rather than prompt problems:\n\n- **Multi-tool workflows time out or drift.** Prefer the RCA tools\n  (`gateway_health_rca`, `blocked_traffic_rca`,\n  `rule_hit_and_shadow_analysis`) — they do the multi-step correlation inside\n  one call, so the model does not have to chain reads and keep rule UUIDs\n  straight.\n- **The model ignores later tool results in a long context.** The firewall log\n  and state table are the two big payloads here; ask narrower questions and use\n  `--limit` / `top` deliberately rather than pulling the whole state table.\n- **The model describes calls instead of making them.** This is usually a\n  runtime/tool-calling-format mismatch, not a prompt problem — check that your\n  client advertises the tools in the format your model was trained on.\n\nFeedback on running this with a specific local model is genuinely useful —\nopen an issue at\n[github.com/AIops-tools/Firewall-AIops](https://github.com/AIops-tools/Firewall-AIops/issues)\nwith the model, runtime, and what went wrong.\n\nFile v0.12.3:references/capabilities.md\n\n# firewall-aiops capabilities\n\n> **35 MCP tools** (26 read, 9 write) across OPNsense (REST `/api/...`, API key+secret\n> via HTTP Basic) and pfSense (REST v2 `/api/v2/...`, API key via `X-API-Key`). The\n> concrete REST paths below are modelled from each project's public API and have not\n> yet been exercised against a live firewall — see `docs/VERIFICATION.md`.\n\nA per-target `platform` field (`opnsense` / `pfsense`) selects the API shape; the same\ntool name resolves to the right path on each firewall via the platform registry.\n\n## System (read)\n\n| Tool | OPNsense path | pfSense path | Returns |\n|------|---------------|--------------|---------|\n| `firmware_status` | `/api/core/firmware/status` | `/api/v2/system/version` | version, product, updates available |\n| `health_status` | `/api/diagnostics/system/systemInformation` | `/api/v2/status/system` | hostname, uptime, CPU %, mem %, load |\n| `interface_status` | `/api/diagnostics/interface/getInterfaceNames` | `/api/v2/status/interfaces` | interfaces with link status + address (down first) |\n| `gateway_status` | `/api/routes/gateway/status` | `/api/v2/status/gateways` | gateways with status, loss %, RTT |\n\n## Rules (read)\n\n| Tool | OPNsense path | pfSense path | Returns |\n|------|---------------|--------------|---------|\n| `list_rules` | `/api/firewall/filter/searchRule` | `/api/v2/firewall/rules` | filter rules normalized (uuid, enabled, action, if, src/dst, evaluations) |\n| `rule_detail` | `/api/firewall/filter/getRule/{uuid}` | `/api/v2/firewall/rule?id=` | one rule's full detail |\n| `rule_stats` | `/api/diagnostics/firewall/pfStatistics` | `/api/v2/firewall/rules` | per-rule hit counts / evaluations, busiest first |\n| `rule_states` | `/api/diagnostics/firewall/queryStates` | `/api/v2/firewall/states` | active state-table entries tied to rules |\n| `pending_changes` | (derived from `searchRule`) | (derived from `firewall/rules`) | the staged rule set `apply_changes` would commit + its lockout assessment |\n\n## NAT (read)\n\n| Tool | Returns |\n|------|---------|\n| `nat_port_forwards` | inbound port-forward (DNAT) rules |\n| `nat_outbound` | outbound (source) NAT mappings |\n| `nat_one_to_one` | 1:1 NAT mappings (external ↔ internal) |\n\n## Aliases (read)\n\n| Tool | Returns |\n|------|---------|\n| `list_aliases` | all aliases (name, type, description, member count) |\n| `alias_entries` | the member entries (hosts/networks/ports) of one alias |\n\n## VPN (read)\n\n| Tool | Returns |\n|------|---------|\n| `wireguard_status` | WireGuard peers with connected state, last handshake, transfer |\n| `openvpn_sessions` | OpenVPN sessions / connected clients (name, address, bytes) |\n| `ipsec_sas` | IPsec security associations (phase-1/phase-2) with state |\n\n## DHCP (read)\n\n| Tool | Returns |\n|------|---------|\n| `dhcp_leases` | active DHCP leases (IP, MAC, hostname, state); `online_only` filter |\n| `dhcp_static_mappings` | DHCP static (reserved) mappings (MAC ↔ IP) |\n\n## Diagnostics (read)\n\n| Tool | Returns |\n|------|---------|\n| `firewall_log` | recent firewall-log entries, optional `action` filter (pass/block/…) |\n| `states_table` | active pf state-table entries |\n| `top_talkers` | busiest source hosts, aggregated from the state table by bytes |\n\n## Flagship analyses (read, pure heuristics)\n\n| Tool | What it does |\n|------|--------------|\n| `gateway_health_rca` | rank gateways by loss (x10) + latency; flag down (status down / 100% loss) and degraded (over threshold); map each to a cause + action. Pass `gateways=` for pure analysis or a target to pull live |\n| `rule_hit_and_shadow_analysis` | never-hit enabled rules (0 evaluations), rules shadowed by an earlier terminating rule, and exact duplicates; each finding names the offending/covering rule uuid |\n| `blocked_traffic_rca` | aggregate blocked log rows by source; classify as port scan (≥10 distinct ports), service brute-force/probe (busy sensitive port 22/3389/…), or generic; with an action |\n\n## Writes (governed)\n\n| Tool | Risk | Path(s) | Notes |\n|------|------|---------|-------|\n| `toggle_rule` | **med** | OPNsense `toggleRule/{uuid}/{0\\|1}`; pfSense PATCH `firewall/rule` | reads the rule first; records undo (restore prior enabled). Staged — run `apply_changes` |\n| `add_alias_entry` | **med** | OPNsense `alias_util/add/{name}`; pfSense `firewall/alias` | captures prior entries; undo removes the added entry |\n| `remove_alias_entry` | **med** | OPNsense `alias_util/delete/{name}`; pfSense `firewall/alias` | captures prior entries; undo adds it back |\n| `kill_states` | **med** | `diagnostics/…/killStates` / `firewall/states` (DELETE, query-filtered) | flush pf states (optionally one source IP) |\n| `restart_service` | **med** | `service/restart/{service}` | restart a firewall service; **refuses** the daemon serving this appliance's own API |\n| `apply_changes` | **HIGH** | `filter/apply` / `firewall/apply` | commit staged config — makes edits live; `dry_run` returns the staged set; **refuses** a provable lockout (`override=True` to force); audited |\n| `reconfigure` | **HIGH** | `filter/savepoint` / `firewall/apply` | reload/commit a subsystem; `dry_run` + audited |\n| `reboot` | **HIGH** | `core/system/reboot` / `diagnostics/reboot` | IRREVERSIBLE — audit only, no undo; `dry_run` |\n\n## Out of scope (v0.1)\n\n- Creating/deleting rules, aliases, or NAT entries from scratch (only toggle + alias\n  entry add/remove today).\n- Cloud security groups and vendor firewall appliances.\n- **Missing something? Open an issue or PR** — contributions welcome.\n\n## Self-lockout guards\n\nA firewall is the one appliance where a routine write severs the connection\ncarrying it — and the recorded undo needs that same connection. Three writes\nrefuse rather than let that happen. All of them are **exact** and **fail open**.\n\n### `restart_service`\n\nRefuses the daemon that answers this platform's own management API — OPNsense\n`nginx` / `configd` / `php-fpm`, pfSense `lighttpd` / `php-fpm`, plus the\ngeneric aliases (`webgui`, `web`, `webserver`, `gui`, `api`) an agent told\n\"restart the web service\" would actually pass. The list lives on the `Platform`\ndescriptor, which already knows which daemon serves its own URLs. Matching is\nexact and case-insensitive; an unrecognised service name is never blocked on a\nguess, so `unbound`, `dhcpd`, `openvpn`, `ipsec` and friends restart normally.\n\n### `apply_changes` / `reconfigure filter`\n\nBoth read the staged rule set first (see `pending_changes`) and refuse when\ncommitting it would provably cut management access. Two mirror-image shapes are\ndangerous:\n\n- a **disabled `pass`** rule that permits management access — applying removes the permit;\n- an **enabled `block`** rule that covers it — applying starts blocking.\n\n\"Provably\" means a literal match on **both** the management host and port.\nEverything short of that fails open with a named warning and proceeds:\n\n| Warning | Meaning |\n|---|---|\n| `ALIAS_DESTINATION` | destination is an alias; it may resolve to the management address |\n| `ANY_DESTINATION` | destination is `any` / a CIDR that may contain the host |\n| `ANY_PORT` | no destination port — may include the management port |\n| `PORT_RANGE` | port expression could not be parsed to a range |\n| `INTERFACE_GROUP` | rule is on `any` / an interface group |\n\n`override=True` proceeds despite a certain finding — for operators with console\naccess who mean it. A rule set that cannot be READ does not block either, but is\nreported as `assessed: false` with the error rather than as a clean bill of\nhealth (a failed probe is not \"nothing pending\").\n\n### `toggle_rule`\n\nRuns the same assessment at staging time — the cheapest point to warn, since the\nrule row is already in hand — and reports `managementImpact` in both directions.\nAdvisory only: staging is never blocked, because `apply_changes` is where the\nchange becomes real and where the refusal lives.\n\n### `dry_run` does not bypass the guards\n\nA `dry_run` whose honest answer is \"this would be refused\" **refuses**. Previewing\nsuccess for a call that is then refused is the preview being wrong, and a weak\nmodel reads the later refusal as transient and retries it. So:\n\n- `apply_changes(dry_run=True)` / `reconfigure(subsystem=\"filter\", dry_run=True)`\n  run the lockout guard before returning, and honour `override=True` on both paths.\n- `restart_service(dry_run=True)` refuses an API-serving service name.\n\n- `toggle_rule(dry_run=True)` reads the rule and reports the same\n  `managementImpact` the real call would.\n\nFail-open semantics are **identical** on both paths — a dry-run never refuses\nwhat the real call would allow.\n\nThe CLI's `rules toggle --dry-run` routes through the governed twin, so it\nreaches the same assessment **and** records the same audit row. The line's\ninvariant is: **a dry_run MAY read; it must never write.** A preview that cannot\nread cannot answer \"would this be refused?\", so reads are expected; the mutating\nPOST/PATCH is the thing that must never happen. (`apply_changes`,\n`reconfigure`, `restart_service`, `kill_states` and `reboot` have no CLI command\n— they are MCP-only — so `rules toggle` is the whole CLI write surface.)\n\n### Two pfSense reads depend on the pfSense-pkg-RESTAPI version\n\n`wireguard_status` and `dhcp_static_mappings` read endpoints that newer\npfSense-pkg-RESTAPI builds serve and older ones do not (`/api/v2/status/wireguard/peers`,\n`/api/v2/services/dhcp_server/static_mappings`). On a build that predates them the\ncall returns a 404 error payload naming the exact path — it is not \"WireGuard is\nnot configured\". Upgrade the package on the firewall to get those surfaces.\nEverything else in this table was exercised against pfSense CE 2.7.2 with\npfSense-pkg-RESTAPI 2.4_3.\n\n### `kill_states` is a lost response, not a lockout\n\nFlushing the pf state table drops the state entry for this tool's own\nconnection, so the call can appear to fail even though the flush ran. Access is\nNOT lost: the permitting rule is untouched and the next call re-establishes\nstate. The dry-run says so in `sessionImpact`, and the result repeats it in\n`note`. **Do not retry blindly** — the flush is likely already done.\n\n### Reversible writes survive a lost response\n\n`toggle_rule`, `add_alias_entry` and `remove_alias_entry` stash their before-state\nvia `capture_prior_state()` immediately before the mutating request. If the\nresponse is lost, the harness records `status=unknown` (not a false `error`) and\ncan still record the inverse, flagged `effectVerified=false`. The irreversible\nwrites (`apply_changes`, `reconfigure`, `restart_service`, `kill_states`,\n`reboot`) declare no inverse, so they capture nothing — there is nothing to\nreplay.\n\nFile v0.12.3:references/cli-reference.md\n\n# firewall-aiops CLI reference\n\n> Covers OPNsense (REST `/api/...`) and pfSense (REST v2 `/api/v2/...`). Responses are\n> validated against mocks; see `docs/VERIFICATION.md` for the live-run checklist.\n\n## Setup & diagnostics\n\n```bash\nfirewall-aiops init                      # interactive wizard (asks for the platform: opnsense/pfsense)\nfirewall-aiops doctor                    # check config, secrets, connectivity\n                                         #   firmware/version query on both platforms\nfirewall-aiops doctor --skip-auth        # config/secret checks only (no network)\nfirewall-aiops mcp                       # start the MCP server (stdio)\n```\n\n## Secrets (encrypted store)\n\n```bash\nfirewall-aiops secret set <target> [--value <secret>]  # store OPNsense secret / pfSense key (hidden prompt if no --value)\nfirewall-aiops secret list                             # list target names with a stored secret (values never shown)\nfirewall-aiops secret rm <target>                      # delete a stored secret\nfirewall-aiops secret migrate                          # import legacy plaintext .env into the encrypted store\nfirewall-aiops secret rotate-password                  # re-encrypt under a new master password\n```\n\n## Overview & rules\n\n```bash\nfirewall-aiops overview                        # one-shot: version + gateway/interface health + rule count\nfirewall-aiops rules list [--interface wan]    # list filter rules (optionally on one interface)\nfirewall-aiops rules show <uuid>               # one rule's full detail\nfirewall-aiops rules toggle <uuid> --disable   # governed write: dry-run + double-confirm\nfirewall-aiops rules toggle <uuid> --enable --dry-run\n```\n\n## Firewall log\n\n```bash\nfirewall-aiops log                             # recent firewall-log entries\nfirewall-aiops log --action block --limit 50   # only blocked traffic\n```\n\n## Notes\n\n- `--target/-t` selects a named target from `config.yaml`; omit for the default (first).\n- `overview`, `rules`, and `log` are the CLI subset; the full read surface (NAT,\n  aliases, VPN, DHCP, diagnostics), the three flagship analyses, and the remaining\n  governed writes (alias entry add/remove, kill_states, restart_service, apply_changes,\n  reconfigure, reboot) are exposed through the MCP server (`firewall-aiops mcp`).\n- High-risk writes (`apply_changes`, `reconfigure`, `reboot`) are labelled risk=high\n  and audited. `FIREWALL_AUDIT_APPROVED_BY` (and `FIREWALL_AUDIT_RATIONALE`) are\n  optional audit annotations, recorded when set but never required.\n\nFile v0.12.3:references/setup-guide.md\n\n# firewall-aiops setup & security guide\n\n> Both **OPNsense** (fully open-source) and **pfSense CE** (free) are self-hostable, so\n> a home lab is the easiest place to run the live checklist in `docs/VERIFICATION.md`.\n> The modelled REST paths are the largest verification debt.\n\n## 1. Install\n\n```bash\nuv tool install firewall-aiops       # or: pipx install firewall-aiops\n```\n\n## 2. What you need per firewall\n\n- **OPNsense** — an **API key + secret** pair (System → Access → Users → edit a user →\n  API keys → create). firewall-aiops talks to the REST API on port **443** and presents\n  the key+secret as HTTP Basic auth. Enable the OPNsense web GUI / API for the account.\n- **pfSense** — the **REST API v2** package (pfSense-pkg-RESTAPI) installed and an **API\n  key** issued by it. The API is under `/api/v2/...` on port **443**; the key is sent in\n  an `X-API-Key` header.\n\n## 3. Onboard with the wizard\n\n```bash\nfirewall-aiops init\n```\n\nThe wizard asks, per target, for the **platform** (`opnsense` / `pfsense`), the\n**host**, the **port** (default 443), the **OPNsense API key** (OPNsense only, saved as\n`username`), and the **secret** — the OPNsense API secret or the pfSense API key.\nNon-secret connection details go to `~/.firewall-aiops/config.yaml`; the secret is\nstored **encrypted** in `~/.firewall-aiops/secrets.enc`.\n\nExample `config.yaml`:\n\n```yaml\ntargets:\n  - name: fw1\n    platform: opnsense\n    host: 192.0.2.1\n    port: 443\n    username: <opnsense-api-key>\n    verify_ssl: true      # the default; set false ONLY for self-signed lab certs\n  - name: edge\n    platform: pfsense\n    host: 192.0.2.2\n    port: 443\n    verify_ssl: true\n    # scheme: http        # https is the default; set http ONLY when the GUI is\n    #                     # published over plain HTTP behind a proxy terminating TLS\n```\n\n## 4. Master password (for non-interactive / MCP use)\n\nThe encrypted store is unlocked by a master password. For the MCP server, CI, or cron,\nexport it so no prompt is needed:\n\n```bash\nexport FIREWALL_AIOPS_MASTER_PASSWORD='...'\n```\n\nOn a TTY the CLI prompts interactively if the env var is unset.\n\n## 5. Verify connectivity\n\n```bash\nfirewall-aiops doctor\n```\n\n`doctor` checks the config file, the encrypted store and its permissions, that each\ntarget has a secret, and (unless `--skip-auth`) live connectivity — a firmware/version\nquery on both platforms.\n\n## Security notes\n\n- The secret (OPNsense API secret / pfSense API key) is **never** written to disk in\n  plaintext — only the scrypt salt and Fernet ciphertext are stored (chmod 600). The\n  master password is never stored.\n- A legacy plaintext env var `FIREWALL_<TARGET_NAME_UPPER>_SECRET` is honoured as a\n  fallback with a deprecation warning (migrate with `firewall-aiops secret migrate`).\n- The secret is presented as HTTP Basic auth (OPNsense) or an `X-API-Key` header\n  (pfSense) at request time and held only in memory; secrets are never logged or echoed.\n- `verify_ssl` defaults to true; set `false` only for self-signed lab certificates.\n- `scheme` defaults to `https`; set `http` only when the GUI is published over plain\n  HTTP behind a proxy that terminates TLS for it.\n- Every MCP tool is audited to `~/.firewall-aiops/audit.db` (relocatable via\n  `FIREWALL_AIOPS_HOME`). High-risk writes (`apply_changes`, `reconfigure`, `reboot`)\n  are labelled risk=high and audited; `FIREWALL_AUDIT_APPROVED_BY` +\n  `FIREWALL_AUDIT_RATIONALE` are optional audit annotations, recorded when set but\n  never required.\n- No webhooks, no telemetry, no outbound calls beyond the configured OPNsense / pfSense\n  REST API. No post-install scripts or background services.\n\nFile v0.12.3:skill-card.md\n\n## Description:\n\nFirewall AIops helps agents inspect and operate OPNsense and pfSense firewalls across health, rules, NAT, VPN, DHCP, logs, root-cause analyses, and audited governed writes.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[zw008](https://clawhub.ai/user/zw008)\n\n### License/Terms of Use:\n\nMIT\n\n## Use Case:\n\nNetwork operators, SREs, and security engineers use this skill to observe OPNsense or pfSense firewall state, diagnose WAN, rule, traffic, VPN, DHCP, and NAT issues, and perform governed firewall changes when authorized.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can perform high-impact firewall writes without an enforceable read-only or approval gate.\n\nMitigation: Start with a read-only OPNsense or pfSense API account, grant write permissions only during an intentional change window, and keep console recovery available for high-risk operations.\n\nRisk: The skill needs access to firewall credentials and stores local firewall state under the user's firewall-aiops directory.\n\nMitigation: Protect the local firewall-aiops directory, use the encrypted secret store, avoid legacy plaintext secret environment variables, and keep the master password out of logs and shared shells.\n\nRisk: TLS verification or plaintext transport choices can weaken protection for firewall API traffic.\n\nMitigation: Enable TLS verification in production and use plaintext HTTP only when TLS is terminated by a trusted proxy.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/zw008/skills/firewall-aiops)\n- [Project homepage](https://github.com/AIops-tools/Firewall-AIops)\n- [Capabilities reference](references/capabilities.md)\n- [CLI reference](references/cli-reference.md)\n- [Setup and security guide](references/setup-guide.md)\n- [Agent guardrails](references/agent-guardrails.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown and structured text with inline shell commands and configuration snippets]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May include firewall observations, RCA findings, dry-run previews, audit-oriented guidance, and rollback steps.]\n\n## Skill Version(s):\n\n0.12.3 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.12.2: 7 files, 19955 bytes\n\nFiles: references/agent-guardrails.md (6900b), references/capabilities.md (10693b), references/cli-reference.md (2530b), references/setup-guide.md (3533b), skill-card.md (2579b), SKILL.md (16120b), _meta.json (134b)\n\nFile v0.12.2:SKILL.md\n\n---\nname: firewall-aiops\nslug: firewall-aiops\ndisplayName: \"Firewall AIops\"\nsummary: \"Governed OPNsense + pfSense firewall ops: rules, NAT, VPN, DHCP, RCA. 35 tools.\"\nlicense: MIT\nhomepage: https://github.com/AIops-tools/Firewall-AIops\ntags: [aiops, mcp, governance, firewall]\ndescription: >\n  Use this skill whenever the user needs to operate an OPNsense or pfSense firewall — a one-shot overview, firmware/health, interfaces and gateways, firewall rules with hit-counts and shadow analysis, NAT (port-forward/outbound/1:1), aliases and their entries, VPN (WireGuard/OpenVPN/IPsec), DHCP leases and static mappings, the firewall log and state table, three flagship RCAs (gateway health, rule hit/shadow, blocked traffic), and governed writes (toggle a rule, add/remove an alias entry, kill states, restart a service, apply/reconfigure to make edits live, reboot).\n  Always use this skill for \"OPNsense\", \"pfSense\", \"firewall rule\", \"port forward\", \"NAT\", \"alias\", \"WireGuard\", \"OpenVPN\", \"IPsec\", \"DHCP lease\", \"firewall log\", \"blocked traffic\", \"why is my WAN down\", \"gateway loss/latency\", \"unused / shadowed rules\", \"apply firewall changes\", \"reboot the firewall\" when the context is an OPNsense/pfSense firewall.\n  Do NOT use when the target is something other than an OPNsense/pfSense firewall (a hypervisor, storage appliance, backup product, container-orchestration cluster, multi-vendor router/switch config, or OT/industrial equipment) — route those to the appropriate other AIops-tools skill. Cloud security groups and vendor firewall appliances are out of scope.\n  Governed firewall operations with a built-in governance harness (audit, policy, token budget, undo, risk-tiers). Live-verified against real OPNsense 26.7 and pfSense CE 2.7.2 on top of the mock test suite; see docs/VERIFICATION.md for exactly what each run proved and what is still untested.\ninstaller:\n  kind: uv\n  package: firewall-aiops\nargument-hint: \"[a rule/alias id, an IP, or describe your firewall task]\"\nallowed-tools:\n  - Bash\nmetadata: {\"openclaw\":{\"requires\":{\"anyBins\":[\"firewall-aiops\",\"uvx\"]},\"optional\":{\"env\":[\"FIREWALL_AIOPS_CONFIG\",\"FIREWALL_AIOPS_MASTER_PASSWORD\"]},\"homepage\":\"https://github.com/AIops-tools/Firewall-AIops\",\"emoji\":\"🛡️\",\"os\":[\"macos\",\"linux\"]}}\ncompatibility: >\n  Standalone, self-governed firewall operations across OPNsense (REST API /api/..., API key+secret via HTTP Basic auth) and pfSense (REST API v2 /api/v2/..., API key via X-API-Key header). Each target in the config names its own platform, and a name-keyed platform registry selects the API shape, so the same tools work on both and one config can span a mixed estate. The governance harness (audit, policy, token/runaway budget, undo, risk-tiers) is bundled in the package — no external skill-family dependency.\n  All write operations are audited to a local SQLite DB under ~/.firewall-aiops/ (relocatable via FIREWALL_AIOPS_HOME).\n  Credentials: the OPNsense API secret (paired with the API key) or the pfSense API key is stored ENCRYPTED in ~/.firewall-aiops/secrets.enc (Fernet/AES-128 + scrypt-derived key) — never plaintext on disk. Run 'firewall-aiops init' to onboard (it asks for the platform), or 'firewall-aiops secret set <target>' to add one. The store is unlocked by a master password from FIREWALL_AIOPS_MASTER_PASSWORD (non-interactive/MCP/CI) or an interactive prompt (CLI on a TTY). A legacy plaintext env var FIREWALL_<TARGET_NAME_UPPER>_SECRET is still honoured as a fallback with a deprecation warning (migrate with 'firewall-aiops secret migrate'). The secret is presented as HTTP Basic auth (OPNsense) or an X-API-Key header (pfSense) at request time and held only in memory; secrets are never logged or echoed.\n  State-changing operations pass through the @governed_tool decorator (budget guard + audit + a descriptive risk-tier label, not a gate). The high-risk commits (apply_changes, reconfigure) and reboot are risk=high with dry_run; reboot is irreversible. Reversible writes (toggle_rule, add_alias_entry, remove_alias_entry) capture the real fetched before-state and record an inverse undo descriptor. Three writes additionally refuse to destroy the tool's own management path: restart_service refuses the daemon serving this appliance's API, and apply_changes / reconfigure refuse a staged rule set that would provably cut management access.\n  Webhooks: none — no outbound network calls beyond the configured OPNsense / pfSense REST API.\n  SSL: verify_ssl defaults to false-friendly for self-signed lab certs; enable for production.\n  Transitive dependencies: httpx (HTTP client) and the MCP SDK. No post-install scripts or background services.\n---\n\n# Firewall AIops\n\n> **Disclaimer**: Community-maintained open-source project, **not affiliated with, endorsed by, or sponsored by the OPNsense project, Deciso, Netgate, or the pfSense project.** OPNsense, pfSense and Netgate are trademarks of their respective owners. Source at [github.com/AIops-tools/Firewall-AIops](https://github.com/AIops-tools/Firewall-AIops) under the MIT license.\n\nGoverned firewall operations — **35 MCP tools** across **OPNsense** (REST `/api/...`)\nand **pfSense** (REST v2 `/api/v2/...`), every one wrapped with the bundled\n`@governed_tool` harness: a local unified audit log under `~/.firewall-aiops/`,\npolicy engine, token/runaway budget guard, undo-token recording, and\ndescriptive risk-tier labelling. A per-target `platform` field selects the API shape,\nso the same tools work on both firewalls and one config can span a mixed estate. The\nOPNsense API secret / pfSense API key is stored **encrypted**\n(`~/.firewall-aiops/secrets.enc`, Fernet + scrypt) — never plaintext on disk.\n\n> **Standalone**: the governance harness is bundled in the package\n> (`firewall_aiops.governance`) — no external skill-family dependency. Both platform\n> halves have been exercised against real firewalls (OPNsense 26.7, pfSense CE 2.7.2)\n> in addition to the mock suite; `docs/VERIFICATION.md` records what each live run\n> proved, and what remains untested on each platform.\n\n## What This Skill Does\n\n| Group | Tools | Count | R/W |\n|-------|-------|:-----:|:---:|\n| **System** | firmware_status, health_status, interface_status, gateway_status | 4 | read |\n| **Rules** | list_rules, rule_detail, rule_stats, rule_states, pending_changes | 5 | read |\n| **NAT** | nat_port_forwards, nat_outbound, nat_one_to_one | 3 | read |\n| **Aliases** | list_aliases, alias_entries | 2 | read |\n| **VPN** | wireguard_status, openvpn_sessions, ipsec_sas | 3 | read |\n| **DHCP** | dhcp_leases, dhcp_static_mappings | 2 | read |\n| **Diagnostics** | firewall_log, states_table, top_talkers | 3 | read |\n| **Flagship analyses** | gateway_health_rca, rule_hit_and_shadow_analysis, blocked_traffic_rca | 3 | read |\n| **Writes** | toggle_rule, add_alias_entry, remove_alias_entry, kill_states, restart_service | 5 | write (med) |\n| **Writes** | apply_changes, reconfigure, reboot | 3 | write (**high**) |\n| **Undo** | undo_list, undo_apply | 2 | read / write |\n\nThe three flagship analyses are transparent heuristics that report their numbers,\nnever a black-box verdict: `gateway_health_rca` ranks gateways by loss + latency and\nmaps each down/degraded one to a cause + action; `rule_hit_and_shadow_analysis` finds\nnever-hit and shadowed/redundant rules; `blocked_traffic_rca` classifies the noisiest\nblocked sources as scan / brute-force / probe.\n\n## Quick Install\n\n```bash\nuv tool install firewall-aiops\nfirewall-aiops init       # wizard: pick platform (opnsense/pfsense) + encrypted secret\nfirewall-aiops doctor\n```\n\nOr as an OpenClaw plugin, which installs this skill and its MCP server together:\n\n```bash\nopenclaw plugins install clawhub:@zw008/firewall-aiops\nopenclaw skills info firewall-aiops          # expect: Visible to model: yes\n```\n\nNeeds `uvx` on `PATH`: the MCP server is fetched with uv, pinned to this release.\n\n## When to Use This Skill\n\n- Get a one-shot snapshot (`overview` / `firmware_status` / `gateway_status`)\n- Investigate a down/degraded WAN (`gateway_health_rca`) → cause + action\n- Audit the ruleset (`rule_stats` hit counts, `rule_hit_and_shadow_analysis` for\n  never-hit / shadowed / redundant rules)\n- Triage hostile traffic (`firewall_log --action block`, `blocked_traffic_rca`,\n  `top_talkers`)\n- Inspect NAT, aliases, VPN tunnels (WireGuard/OpenVPN/IPsec), and DHCP leases\n- Safely toggle a rule or edit an alias (`toggle_rule` / `add_alias_entry` /\n  `remove_alias_entry`, reversible + undo-recorded), then **make it live** with\n  `apply_changes` (dry-run + audit)\n\n**Do NOT use when** the target is not an OPNsense/pfSense firewall — route hypervisor,\nstorage, backup, cluster, multi-vendor router/switch config, or OT/industrial work to\nthe appropriate other AIops-tools skill.\n\n## Related Skills — Skill Routing\n\n| If the user wants… | Use |\n|--------------------|-----|\n| OPNsense / pfSense firewall ops | **firewall-aiops** (this skill) |\n| A non-firewall platform (hypervisor, storage, backup, cluster, network config, OT edge) | the appropriate **other AIops-tools** skill |\n| Cloud security groups / vendor firewall appliances | out of scope for this tool |\n\n## Common Workflows\n\nThe CLI surface is `init` / `doctor` / `overview` / `log` / `rules` / `secret` / `undo`;\nthe flagship RCAs, NAT / alias / VPN / DHCP reads, and the remaining governed writes are\nMCP tools (start the server with `firewall-aiops mcp`). Recipes below say which is which.\n\n### 1. \"The internet keeps dropping\" — WAN gateway triage\n\n1. `firewall-aiops doctor` → confirm the firewall is reachable and the secret unlocks\n   (a red doctor means you are debugging credentials, not the WAN).\n2. `firewall-aiops overview` → one-shot: firmware/version, gateway + interface health,\n   rule count. Down interfaces sort first.\n3. MCP `gateway_health_rca` → gateways ranked worst-first, each row citing its measured\n   loss % and RTT, mapped to a cause (last-mile loss / congestion / latency / hard down)\n   and a concrete action.\n4. If the RCA points at a stuck daemon rather than the circuit, MCP\n   `restart_service(service=\"dpinger\", dry_run=true)` to preview, then re-run for real\n   (medium risk, audited, undo-recorded).\n5. Re-run `firewall-aiops overview` to confirm the gateway came back green.\n6. **Failure branch**: if the restart does not clear it, the gateway is genuinely down\n   upstream — stop touching the firewall and escalate to the ISP. If the restart made\n   things worse, `firewall-aiops undo list` → `firewall-aiops undo apply <\n\nArchive v0.12.1: 7 files, 19957 bytes\n\nFiles: references/agent-guardrails.md (6900b), references/capabilities.md (10693b), references/cli-reference.md (2530b), references/setup-guide.md (3533b), skill-card.md (2571b), SKILL.md (16126b), _meta.json (134b)\n\nArchive v0.12.0: 7 files, 20006 bytes\n\nFiles: references/agent-guardrails.md (6900b), references/capabilities.md (10693b), references/cli-reference.md (2530b), references/setup-guide.md (3533b), skill-card.md (3045b), SKILL.md (15810b), _meta.json (134b)\n\nArchive v0.11.0: 7 files, 19814 bytes\n\nFiles: references/agent-guardrails.md (6900b), references/capabilities.md (10693b), references/cli-reference.md (2530b), references/setup-guide.md (3533b), skill-card.md (2602b), SKILL.md (15921b), _meta.json (134b)\n\nArchive v0.10.0: 7 files, 19816 bytes\n\nFiles: references/agent-guardrails.md (6900b), references/capabilities.md (10693b), references/cli-reference.md (2530b), references/setup-guide.md (3533b), skill-card.md (2687b), SKILL.md (15921b), _meta.json (134b)\n\nArchive v0.9.0: 7 files, 19683 bytes\n\nFiles: references/agent-guardrails.md (6900b), references/capabilities.md (10103b), references/cli-reference.md (2530b), references/setup-guide.md (3533b), skill-card.md (3054b), SKILL.md (15791b), _meta.json (133b)\n\nArchive v0.8.0: 7 files, 19553 bytes\n\nFiles: references/agent-guardrails.md (6900b), references/capabilities.md (10103b), references/cli-reference.md (2530b), references/setup-guide.md (3533b), skill-card.md (2717b), SKILL.md (15791b), _meta.json (133b)","readmeExcerpt":"Skill: firewall-aiops Owner: zw008 Summary: Use this skill whenever the user needs to operate an OPNsense or pfSense firewall — a one-shot overview, firmware/health, interfaces and gateways, firewall rules with hit-counts and shadow analysis, NAT (port-forward/outbound/1:1), aliases and their entries, VPN (WireGuard/OpenVPN/IPsec), DHCP leases and static mappings, the firewall log and state table, three flagship RCAs","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"uv tool install firewall-aiops\nfirewall-aiops init       # wizard: pick platform (opnsense/pfsense) + encrypted secret\nfirewall-aiops doctor"},{"language":"bash","snippet":"openclaw plugins install clawhub:@zw008/firewall-aiops\nopenclaw skills info firewall-aiops          # expect: Visible to model: yes"},{"language":"text","snippet":"You operate an OPNsense or pfSense firewall through the firewall-aiops MCP tools.\n\nTOOL USE\n- Before answering any question about the current firewall, you MUST call a\n  tool. Never answer from memory or assumption.\n- Actually invoke the tool. Do not describe the call you would make, and do not\n  emit an example JSON response in place of calling it.\n- If a tool call fails, report the real error verbatim. Never fill the gap with\n  a plausible-sounding answer.\n\nREADING RESULTS\n- Read the whole result before concluding. If a result contains a \"truncated\"\n  field that is true, say so and re-run with a higher limit instead of treating\n  the partial result as complete.\n- Of the three RCAs, only `blocked_traffic_rca`'s order is checkable (by `hits`). Do not read\n  priority off the position of a gateway finding, and do not look for a number on a rule\n  finding — there is none; read `hitCountersUnavailable` to see whether \"never hit\" was even\n  measurable.\n- A null field means neither platform returned that value. Report it as \"not\n  available\" — never infer it. In particular, a rule with a null \"interface\" is\n  not a rule on an interface named \"none\".\n- Report values exactly as returned. Do not normalise, translate, or prettify\n  rule actions, gateway statuses, or interface names.\n- A gateway whose status is \"none\" is unmonitored, not down. A gateway with no\n  status field at all is unknown — say so rather than calling it healthy.\n\n- Only `toggle_rule` has a CLI command. `apply_changes`, `reconfigure`, `reboot`,\n  `restart_service`, `kill_states` and the alias writes are MCP-only and nothing will ask\n  you to confirm them: call with `dry_run=True` first and wait for an explicit go-ahead.\n\nSCOPE\n- Separate observation from interpretation. State what the tools returned, then\n  any interpretation, clearly marked as such.\n- Do not assert that traffic is being blocked by a specific rule unless a log\n  entry or the shadow analysis actually names that rule.\n- Do not add generic fi"},{"language":"bash","snippet":"# Give the OPNsense/pfSense API user a read-only role, then:\nfirewall-aiops doctor"},{"language":"bash","snippet":"export FIREWALL_AUDIT_APPROVED_BY=\"your.name@example.com\"\nexport FIREWALL_AUDIT_RATIONALE=\"scheduled maintenance window 2026-07-20\""},{"language":"bash","snippet":"firewall-aiops init                      # interactive wizard (asks for the platform: opnsense/pfsense)\nfirewall-aiops doctor                    # check config, secrets, connectivity\n                                         #   firmware/version query on both platforms\nfirewall-aiops doctor --skip-auth        # config/secret checks only (no network)\nfirewall-aiops mcp                       # start the MCP server (stdio)"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: firewall-aiops\nslug: firewall-aiops\ndisplayName: \"Firewall AIops\"\nsummary: \"Governed OPNsense + pfSense firewall ops: rules, NAT, VPN, DHCP, RCA. 35 tools.\"\nlicense: MIT\nhomepage: https://github.com/AIops-tools/Firewall-AIops\ntags: [aiops, mcp, governance, firewall]\ndescription: >\n  Use this skill whenever the user needs to operate an OPNsense or pfSense firewall — a one-shot overview, firmware/health, interfaces and gateways, firewall rules with hit-counts and shadow analysis, NAT (port-forward/outbound/1:1), aliases and their entries, VPN (WireGuard/OpenVPN/IPsec), DHCP leases and static mappings, the firewall log and state table, three flagship RCAs (gateway health, rule hit/shadow, blocked traffic), and governed writes (toggle a rule, add/remove an alias entry, kill states, restart a service, apply/reconfigure to make edits live, reboot).\n  Always use this skill for \"OPNsense\", \"pfSense\", \"firewall rule\", \"port forward\", \"NAT\", \"alias\", \"WireGuard\", \"OpenVPN\", \"IPsec\", \"DHCP lease\", \"firewall log\", \"blocked traffic\", \"why is my WAN down\", \"gateway loss/latency\", \"unused / shadowed rules\", \"apply firewall changes\", \"reboot the firewall\" when the context is an OPNsense/pfSense firewall.\n  Do NOT use when the target is something other than an OPNsense/pfSense firewall (a hypervisor, storage appliance, backup product, container-orchestration cluster, multi-vendor router/switch config, or OT/industrial equipment) — route those to the appropriate other AIops-tools skill. Cloud security groups and vendor firewall appliances are out of scope.\n  Governed firewall operations with a built-in governance harness (audit, policy, token budget, undo, risk-tiers). Live-verified against real OPNsense 26.7 and pfSense CE 2.7.2 on top of the mock test suite; see docs/VERIFICATION.md for exactly what each run proved and what is still untested.\ninstaller:\n  kind: uv\n  package: firewall-aiops\nargument-hint: \"[a rule/alias id, an IP, or describe your firewall task]\"\nallowed-tools:\n  - Bash\nmetadata: {\"openclaw\":{\"requires\":{\"anyBins\":[\"firewall-aiops\",\"uvx\"]},\"optional\":{\"env\":[\"FIREWALL_AIOPS_CONFIG\",\"FIREWALL_AIOPS_MASTER_PASSWORD\"]},\"homepage\":\"https://github.com/AIops-tools/Firewall-AIops\",\"emoji\":\"🛡️\",\"os\":[\"macos\",\"linux\"]}}\ncompatibility: >\n  Standalone, self-governed firewall operations across OPNsense (REST API /api/..., API key+secret via HTTP Basic auth) and pfSense (REST API v2 /api/v2/..., API key via X-API-Key header). Each target in the config names its own platform, and a name-keyed platform registry selects the API shape, so the same tools work on both and one config can span a mixed estate. The governance harness (audit, policy, token/runaway budget, undo, risk-tiers) is bundled in the package — no external skill-family dependency.\n  All write operations are audited to a local SQLite DB under ~/.firewall-aiops/ (relocatable via FIREWALL_AIOPS_HOME).\n  Credentials: the OPNsense API secret (paired with the API key) or the pfSense API key i"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7b067awq2s97bn3d7p5qfhw5827pxc\",\n  \"slug\": \"firewall-aiops\",\n  \"version\": \"0.12.5\",\n  \"publishedAt\": 1789601135182\n}"},{"path":"references/agent-guardrails.md","content":"# Agent guardrails — running firewall-aiops with a smaller / local model\n\nIf you drive these tools with a local model (Llama, Qwen, Mistral … via Goose,\nOllama, LM Studio, or any OpenAI-compatible runtime), you will get noticeably\nbetter results with a short system prompt. This page gives you one, and — more\nimportantly — tells you which guardrails you **no longer need to write**, because\nthe tool now enforces them itself.\n\nThe distinction matters. A guardrail in a prompt is a request. A guardrail in the\nharness is a guarantee. Anything below that we could move into the harness, we did.\n\n## Authorization is not this tool's job — decide it where it belongs\n\nWhether a write should happen is your decision, or the account's. The tool does\nnot gate it — there is no read-only switch and no approval prompt to configure.\nThe two right places to control read vs write:\n\n- **The account you connect with.** Give the OPNsense/pfSense API user a\n  read-only role. A write then fails at the server, which is the only place the\n  permission actually lives — no skill-side flag can be argued around by a model,\n  but a revoked permission cannot be.\n- **Your agent's system prompt.** If you want an observe-only session, tell the\n  model not to call the write tools (they are clearly tagged `[WRITE]`).\n\nWhat the tool *does* guarantee is that you can always see what happened:\n\n## What the tool now enforces — do not waste prompt budget on these\n\n| You might be tempted to prompt | Why you don't need to |\n|---|---|\n| \"Never restart the web GUI / lock yourself out\" | **Already enforced.** `restart_service` refuses the daemon serving this appliance's own API (`nginx`, `lighttpd`, `configd`, `webgui`, ...), and `apply_changes` / `reconfigure` refuse a staged rule set that would provably cut management access. Both are exact and fail open — see `capabilities.md`. Do not spend prompt budget on it. |\n| \"Don't invent a value when a field is missing\" | OPNsense and pfSense populate different keys for the same concept. A field neither platform returned comes back as `null`, never as `\"\"`. Absent and empty are distinguishable in the payload. |\n| \"Tell me if the output was cut off\" | `firewall_log`, `states_table` and `top_talkers` all return `{\"<items>\": [...], \"returned\": N, \"limit\": L, \"truncated\": true/false}` — the list key is `entries`, `states` and `topTalkers` respectively. Truncation is measured, not guessed from a length coincidence. |\n| \"Make it show the number it judged on\" | Gateway and blocked-source entries carry the numbers they were judged on — `lossPercent` and `rttMs` for a gateway (`lossPct`/`latencyMs` are the *thresholds* they were compared against, reported separately under `thresholds`), `hits`, `distinctPorts` and `topPort` for a blocked source — so those claims can be checked against a figure. `blocked_traffic_rca` orders `topSources` by `hits`, which is in the payload. Rule findings are qualitative: they carry `uuid`, `description`, `interface`, `shadowedBy`/"},{"path":"references/capabilities.md","content":"# firewall-aiops capabilities\n\n> **35 MCP tools** (26 read, 9 write) across OPNsense (REST `/api/...`, API key+secret\n> via HTTP Basic) and pfSense (REST v2 `/api/v2/...`, API key via `X-API-Key`). The\n> concrete REST paths below are modelled from each project's public API and have not\n> yet been exercised against a live firewall — see `docs/VERIFICATION.md`.\n\nA per-target `platform` field (`opnsense` / `pfsense`) selects the API shape; the same\ntool name resolves to the right path on each firewall via the platform registry.\n\n## System (read)\n\n| Tool | OPNsense path | pfSense path | Returns |\n|------|---------------|--------------|---------|\n| `firmware_status` | `/api/core/firmware/status` | `/api/v2/system/version` | version, product, updates available |\n| `health_status` | `/api/diagnostics/system/systemInformation` | `/api/v2/status/system` | hostname, uptime, CPU %, mem %, load |\n| `interface_status` | `/api/diagnostics/interface/getInterfaceNames` | `/api/v2/status/interfaces` | interfaces with link status + address (down first) |\n| `gateway_status` | `/api/routes/gateway/status` | `/api/v2/status/gateways` | gateways with status, loss %, RTT |\n\n## Rules (read)\n\n| Tool | OPNsense path | pfSense path | Returns |\n|------|---------------|--------------|---------|\n| `list_rules` | `/api/firewall/filter/searchRule` | `/api/v2/firewall/rules` | filter rules normalized (uuid, enabled, action, if, src/dst, evaluations) |\n| `rule_detail` | `/api/firewall/filter/getRule/{uuid}` | `/api/v2/firewall/rule?id=` | one rule's full detail |\n| `rule_stats` | `/api/diagnostics/firewall/pfStatistics` | `/api/v2/firewall/rules` | per-rule hit counts / evaluations, busiest first |\n| `rule_states` | `/api/diagnostics/firewall/queryStates` | `/api/v2/firewall/states` | active state-table entries tied to rules |\n| `pending_changes` | (derived from `searchRule`) | (derived from `firewall/rules`) | the staged rule set `apply_changes` would commit + its lockout assessment |\n\n## NAT (read)\n\n| Tool | Returns |\n|------|---------|\n| `nat_port_forwards` | inbound port-forward (DNAT) rules |\n| `nat_outbound` | outbound (source) NAT mappings |\n| `nat_one_to_one` | 1:1 NAT mappings (external ↔ internal) |\n\n## Aliases (read)\n\n| Tool | Returns |\n|------|---------|\n| `list_aliases` | all aliases (name, type, description, member count) |\n| `alias_entries` | the member entries (hosts/networks/ports) of one alias |\n\n## VPN (read)\n\n| Tool | Returns |\n|------|---------|\n| `wireguard_status` | WireGuard peers with connected state, last handshake, transfer |\n| `openvpn_sessions` | OpenVPN sessions / connected clients (name, address, bytes) |\n| `ipsec_sas` | IPsec security associations (phase-1/phase-2) with state |\n\n## DHCP (read)\n\n| Tool | Returns |\n|------|---------|\n| `dhcp_leases` | active DHCP leases (IP, MAC, hostname, state); `online_only` filter |\n| `dhcp_static_mappings` | DHCP static (reserved) mappings (MAC ↔ IP) |\n\n## Diagnostics (read)\n\n| Tool | Returns |\n|------|---------"},{"path":"references/cli-reference.md","content":"# firewall-aiops CLI reference\n\n> Covers OPNsense (REST `/api/...`) and pfSense (REST v2 `/api/v2/...`). Responses are\n> validated against mocks; see `docs/VERIFICATION.md` for the live-run checklist.\n\n## Setup & diagnostics\n\n```bash\nfirewall-aiops init                      # interactive wizard (asks for the platform: opnsense/pfsense)\nfirewall-aiops doctor                    # check config, secrets, connectivity\n                                         #   firmware/version query on both platforms\nfirewall-aiops doctor --skip-auth        # config/secret checks only (no network)\nfirewall-aiops mcp                       # start the MCP server (stdio)\n```\n\n## Secrets (encrypted store)\n\n```bash\nfirewall-aiops secret set <target> [--value <secret>]  # store OPNsense secret / pfSense key (hidden prompt if no --value)\nfirewall-aiops secret list                             # list target names with a stored secret (values never shown)\nfirewall-aiops secret rm <target>                      # delete a stored secret\nfirewall-aiops secret migrate                          # import legacy plaintext .env into the encrypted store\nfirewall-aiops secret rotate-password                  # re-encrypt under a new master password\n```\n\n## Overview & rules\n\n```bash\nfirewall-aiops overview                        # one-shot: version + gateway/interface health + rule count\nfirewall-aiops rules list [--interface wan]    # list filter rules (optionally on one interface)\nfirewall-aiops rules show <uuid>               # one rule's full detail\nfirewall-aiops rules toggle <uuid> --disable   # governed write: dry-run + double-confirm\nfirewall-aiops rules toggle <uuid> --enable --dry-run\n```\n\n## Firewall log\n\n```bash\nfirewall-aiops log                             # recent firewall-log entries\nfirewall-aiops log --action block --limit 50   # only blocked traffic\n```\n\n## Notes\n\n- `--target/-t` selects a named target from `config.yaml`; omit for the default (first).\n- `overview`, `rules`, and `log` are the CLI subset; the full read surface (NAT,\n  aliases, VPN, DHCP, diagnostics), the three flagship analyses, and the remaining\n  governed writes (alias entry add/remove, kill_states, restart_service, apply_changes,\n  reconfigure, reboot) are exposed through the MCP server (`firewall-aiops mcp`).\n- High-risk writes (`apply_changes`, `reconfigure`, `reboot`) are labelled risk=high\n  and audited. `FIREWALL_AUDIT_APPROVED_BY` (and `FIREWALL_AUDIT_RATIONALE`) are\n  optional audit annotations, recorded when set but never required."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":2272,"uniquenessScore":39,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-09T16:47:12.210Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-09T16:47:12.210Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-09T22:50:59.529Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}