inspectre --:--:--

$ cat plugin.md | less

Build a plugin

An InSpectre plugin is a single declarative manifest — JSON or YAML. There is no plugin code to write, compile or execute: the manifest declares HTTP / file / SNMP operations, and the InSpectre plugin engine runs them on a schedule (or in response to events), then maps the results into your device inventory.

Plugins are declarative

If you have used other monitoring tools you may expect imperative code hooks like on_device_discovered() or on_scan_complete(). InSpectre's equivalent is the declarative event-hooks map: you bind an InSpectre event to a named action the engine runs. This keeps community plugins safe to share — a manifest can only make the network calls it declares, against credentials the user explicitly enters.

Imperative hook you might expectInSpectre event key
on_device_discovereddevice.new
on_device_onlinedevice.online
on_device_offlinedevice.offline
on_port_opened / on_scan_completeport.opened
on_vulnerability_foundvuln.found (+ vuln.critical, vuln.high)
on_device_blocked / on_device_unblockeddevice.blocked / device.unblocked

Quick start

  • Copy examples/plugins/TEMPLATE.yaml (or the JSON hello-world.json).
  • Set a unique lowercase id, then edit config_schema, endpoints and actions to match your target API.
  • In InSpectre: Settings → Plugins → Upload Plugin, choose your file.
  • Open the plugin, fill in config, click Test Connection.
  • Toggle Enabled. Polling starts on the next cycle; blocking plugins become selectable under Settings → Security Responses → Blocking Method.

A minimal discovery plugin is just an endpoint, one action, and a polling block:

my-router.json — minimal discovery plugin
{
  "id": "my-router",
  "name": "My Router",
  "version": "1.0.0",
  "capabilities": ["discovery"],
  "config_schema": [
    { "key": "host", "label": "Base URL", "type": "url", "default": "http://192.168.0.1", "required": true },
    { "key": "api_key", "label": "API Key", "type": "password", "default": "", "required": true }
  ],
  "endpoints": { "base_url": "{host}", "auth": "api-key-header", "api_key_header": "X-API-Key" },
  "actions": {
    "get_leases": {
      "method": "GET",
      "path": "/api/dhcp/leases",
      "response_mapping": { "root_path": "leases",
        "fields": { "mac": "mac_address", "ip": "ip_address", "name": "hostname" } }
    }
  },
  "polling": { "action": "get_leases", "interval_seconds": 120 }
}

Manifest reference

FieldReqDescription
idUnique slug — lowercase letters, digits, hyphens.
nameDisplay name.
versionSemVer, e.g. 1.0.0.
capabilitiesWhat the plugin does — see below.
config_schemaUser-configurable fields. May be empty.
endpointsBase URL, auth, headers. Required for HTTP/SNMP plugins.
actionsNamed operations the engine can run.
event_hooksMap InSpectre event → action name.
pollingScheduled action(s).
data_mappingtag_fields to promote onto device tags.

Capabilities

Declare what your plugin genuinely does — the engine uses these to decide which flows it joins. Only discovery/presence plugins have poll results written to the inventory; only blocking plugins appear as block methods.

discovery

MAC/IP/hostname rows for the inventory.

enrichment

Adds vendor, type, tags to known devices.

presence

Reports whether a device is online.

dns

Is a DNS server/resolver (AdGuard, Pi-hole).

traffic

Provides DNS query logs / flow data.

blocking

Can enforce per-device blocks.

firewall

Controls a stateful firewall.

export

Sends InSpectre state to an external system.

notification

Delivers alerts.

Config schema

Each entry renders a field in the plugin's config form. Values become {key} placeholders usable in endpoints and actions.

Field types: string, password, integer, boolean, select, multiline, url, filepath.

  • password values are encrypted at rest (Fernet, derived from the server SECRET_KEY) and shown as **redacted** when reading config back via the API.
  • multiline renders a textarea (e.g. a newline-separated keyword list).
  • filepath is a container-internal path — mount the file into the backend container via volumes:.

Event hooks

Bind an InSpectre event to an action. When the event fires, the engine runs the action asynchronously (fire-and-forget) for every enabled plugin that declares a matching hook.

event_hooks
"event_hooks": {
  "device.new":     "notify_action",
  "vuln.critical":  "notify_action",
  "device.offline": "notify_action"
}
EventFires whenContext
device.newA device (or new interface) is first seenmac, name, ip
device.onlineA device comes back onlinemac, name, ip
device.offlineA device goes offlinemac, name, ip
port.openedA new open port is detectedmac, name, ip, ports
vuln.foundA vuln scan finds issuesmac, name, ip, vulns
device.blockedA device was blockedmac, ip
device.unblockedA device was unblockedmac, ip
Don't hook a blocking plugin's own device.blocked → block_client — the blocking coordinator already calls it directly; hooking it again would double-fire. Event hooks are for reacting to events (e.g. sending a notification).

Polling

Run action(s) on a schedule. Results are upserted into the inventory when the plugin has discovery or presence capability.

KeyDescription
actionSingle action name to poll.
actionsArray of action names (results merged, last write wins per MAC).
interval_secondsPoll interval. Default 300.
run_on_startupPolling begins after a ~30 s startup grace.
max_rate_per_minuteOptional per-action rate cap.

The blocking contract

A blocking plugin must declare block_client and unblock_client actions. Once enabled, it becomes selectable under Settings → Security Responses → Blocking Method, and the blocking coordinator calls those actions directly when you block or unblock a device. Blocking actions emit device.blocked / device.unblocked events on success, and may use read-modify-write list directives for APIs that take an allow/deny list.

Built-in plugins

The shipped manifests in backend/plugins/builtin/ are the best real-world examples — read them alongside this guide.

PluginIDCapabilities
AdGuard Homeadguard-homediscovery, enrichment, dns, traffic, blocking
Pi-holepiholediscovery, enrichment, dns, traffic, blocking
TP-Link Omadatplink-omadadiscovery, presence, blocking, enrichment
Home Assistanthome-assistantexport, notification
OPNsenseopnsensediscovery, enrichment, blocking, firewall
pfSensepfsensediscovery, enrichment, blocking, firewall

Install & test

01

Author

Copy the template, set id & config.

02

Upload

Settings → Plugins → Upload.

03

Configure

Fill fields, Test Connection.

04

Enable

Toggle on; polling starts next cycle.

05

Use

Discovery feeds inventory; blocking appears as a method.

The full manifest reference — template substitution, dependency chains, session extraction, response mapping, file & SNMP plugins and webhook-triggered actions — lives in plugin.md with annotated examples in examples/plugins/.

A note on safety

Because a plugin is just a manifest, it can only perform the network operations it declares, against the endpoints and credentials you enter. There is no arbitrary code execution inside the backend. That said, community plugins are not audited by the InSpectre project — review a manifest before uploading it, the same way you would any config that holds your credentials.