Skip to main content

Kanary

Image

Kanary is a Python-based alerting, notification, and reliability monitoring runtime inspired by the historical “canary in a coal mine” You define three kinds of plugins in Python:

  • Source Reads values from a system, database, API, or device.
  • Rule Evaluates those values and decides whether an alert should fire.
  • Output Sends alert events to humans or other systems.

This separation keeps collection, evaluation, and notification independent, so monitoring definitions stay manageable as the system grows.

Installation

The normal installation method is PyPI:

pip install kanary

If you use uv, this also works:

uv tool install kanary

Then kanary and kanaryctl executables will be installed.

Installing from a source checkout is still supported, but it should be treated as a development workflow:

git clone https://github.com/mzks/kanary
cd kanary
uv sync
uv run python -m kanary ./demo

Docker

Published release images are available from GitHub Container Registry for linux/amd64 and linux/arm64:

docker pull ghcr.io/mzks/kanary:0.7.2

Mount a plugin directory read-only and keep the SQLite state database in a named volume:

docker run --name kanary --restart unless-stopped \
  -p 8000:8000 \
  -v "$(pwd)/plugins:/etc/kanary/plugins:ro" \
  -v kanary-data:/var/lib/kanary \
  ghcr.io/mzks/kanary:0.7.2

The image runs the equivalent of:

kanary /etc/kanary/plugins \
  --state-db /var/lib/kanary/kanary.db \
  --api-port 8000

Open http://127.0.0.1:8000/viewer after the container starts. Replace 0.7.2 with the release you intend to deploy; latest is also published for tagged releases.

What To Do First

Start by running the smallest example from demo/.

kanary ./demo

Then move in this order:

  1. Read demo/basic_monitoring.py to understand the smallest possible Source, Rule, and Output.
  2. Read docs/getting_started.md and work through the examples in examples/getting_started.py.
  3. Browse examples/ for PostgreSQL, Discord, peer monitoring, and remote alert import.
  4. Create your own plugins/ directory and start with one Source and one Rule.

Minimal Example

The smallest working example is in demo/basic_monitoring.py. Make a directory to place plugin files then put the following scripts.

from datetime import datetime, timezone

import kanary


@kanary.source(source_id="demo", interval=10.0)
class DemoSource:
    def poll(self):
        return kanary.inputs([
            ("temperature", 23.4, datetime.now(timezone.utc)),
        ])


@kanary.rule(
    rule_id="demo.temperature.high",
    inputs="demo:temperature",
    severity=kanary.WARN,
    tags=["demo"],
)
class DemoTemperatureHigh:
    threshold = 25.0

    def evaluate(self, ctx):
        temperature = ctx.value()
        if temperature is None:
            return kanary.ok("temperature is missing")
        return kanary.error_if(
            temperature > self.threshold,
            f"temperature={temperature} is higher than {self.threshold}",
        ) or kanary.ok(
            f"temperature={temperature} is within limit",
        )


@kanary.output(output_id="console")
class ConsoleOutput:
    def emit(self, event):
        print(
            event.rule_id,
            event.current_state.value,
            event.current_severity.name,
            event.transition.value if event.transition else "-",
            event.message,
        )

In this example, you only implement the minimum interface:

  • a source that returns values
  • a rule that evaluates them
  • an output that reacts to alert events

Internally, Kanary handles plugin loading, periodic source polling, rule evaluation, alert state tracking, the HTTP API, and the Web viewer.

If you want shorter definitions later, you can switch to built-in helper classes such as RangeRule, StaleRule, and ThresholdRule. Users can create plugin class factory too.

For sources, the usual public API is kanary.inputs(...), kanary.no_data(...), kanary.no_update(...), and kanary.skip(...). For rules, the usual public API is kanary.ok(...), kanary.firing(...), kanary.warn(...), kanary.error(...), and kanary.critical(...). kanary.SourceResult(...) and kanary.Evaluation(...) remain available as advanced forms.

Running Kanary

Basic run:

kanary ./demo

Check the installed version:

kanary --version
kanaryctl --version

run is optional. These are equivalent:

kanary ./demo
kanary run ./demo
python -m kanary ./demo
python -m kanary run ./demo

Change the API and Web viewer port:

kanary ./demo --api-port 8000

Expose the API and Web viewer on the LAN:

kanary ./demo --api-host 0.0.0.0 --api-port 8000

Persist history in SQLite:

kanary ./demo --state-db ./var/kanary.db

Run a shadow instance that evaluates routing without calling Output emit():

kanary ./demo --api-port 8001 --node-id demo-shadow --no-output-emit

The Web viewer is available at:

http://<host>:8000/viewer

See all CLI options with:

kanary --help
kanaryctl help

Quick diagnostic commands:

kanaryctl test-poll demo
kanaryctl test-evaluate demo.temperature.high --print-template
kanaryctl test-evaluate demo.temperature.high --payload-json '{"inputs":{"demo:temperature":{"value":30.0,"timestamp":"2026-05-29T00:00:00+00:00"}},"status":"ok"}'
kanaryctl test-fire demo.temperature.high --state FIRING --reason "delivery test"

Rule code should normally use input-based access such as ctx.value() for a single input or ctx.inputs() for multiple inputs. test-evaluate is the exception: it accepts an inputs map keyed by fully-qualified input names. Use kanaryctl test-evaluate <rule_id> --print-template to print a canonical payload skeleton before writing test data.

Targeted plugin reload:

kanaryctl reload --rule 'demo.*'
kanaryctl reload --source 'demo*'
kanaryctl reload --output 'mail*'
kanaryctl reload --dirty
kanaryctl reload --all
kanaryctl reload --full

dirty is a practical hint, not a complete dependency tracker. Kanary detects plugin definition changes and watched-root static imports, but it does not try to prove every same-file helper change or dynamic dependency. If you changed code intentionally, apply the relevant reload explicitly. all reruns full plugin discovery even when no watched Python file changed. full performs an in-process engine restart and reinitializes all sources, rules, and outputs.

Environment Variables

Kanary does not require any environment variables by default. You can use these when needed:

  • KANARY_SQLITE_PATH Alternative way to set the SQLite database path.
  • KANARY_API_URL Default API base URL for kanaryctl.
  • KANARY_API_HOST Bind host for the local API and Web viewer. The default is 0.0.0.0.
  • KANARY_NODE_ID Optional node identifier for peer export and import. If unset, Kanary uses the hostname.

The KANARY_* prefix is primarily reserved for Kanary engine/runtime settings. Example plugins in this repository usually read connection details from local files such as *_config.toml next to the plugin script instead of relying on additional KANARY_* variables. The recommended helper is kanary.load_toml(...), which resolves relative paths against the caller script's directory. Those local config files are not watched for auto-reload, so after editing them you should run an explicit kanaryctl reload ....

Demo And Examples

Smallest example:

More realistic examples:

demo/ is for the first working run. examples/ is closer to real deployments and includes helper classes, remote monitoring, PostgreSQL wide/long table patterns, and webhook outputs.

Web Viewer

Kanary includes a built-in Web viewer. The operational surface, however, is the HTTP API. The viewer is the standard UI built on top of that API, and you can replace it with your own tooling if needed.

Documentation

Japanese versions are available as _ja documents, for example README_ja.md.

Metadata

Release files for kanary 0.7.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for kanary 0.7.2
File Size Uploaded Provenance Actions
kanary-0.7.2.tar.gz 127.0 kB Without provenance Details for kanary-0.7.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for kanary 0.7.2
File Interpreter ABI Platform Actions
kanary-0.7.2-py3-none-any.whl Python 3 none any Details for kanary-0.7.2-py3-none-any.whl

Total release size: 230.2 kB

Release files / kanary-0.7.2.tar.gz

Download URL kanary-0.7.2.tar.gz
Size 127.0 kB
Tags Source
SHA-256 checksum
How to use checksums
15ccc37587d35a3e6f7fe234bb143714d22e381e1463de53817c475dfa89e212
BLAKE2b-256 checksum
How to use checksums
c9604bec39696010b14ffa4040b0de0b7cfabfa7bf420348fccac5bdb61a83b2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.11

Release files / kanary-0.7.2-py3-none-any.whl

Download URL kanary-0.7.2-py3-none-any.whl
Size 103.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
325bd7cb483cccbb0272e22ac390743a06d087c1669489a8465ba1992b158fc5
BLAKE2b-256 checksum
How to use checksums
f8d0f6e99fa74f11c895399141421f907bb0409e736db2087ffbf1df11f17ab4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.11

Security for kanary 0.7.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page