← Back to Plugins
Tools

Signalplane

sebsebli By sebsebli 👁 17 views ▲ 0 votes

Signalplane gives AI agents a future tense. Self-hosted event watching for weather, security, releases, markets, social, sports, RSS & more. Define rules, detect signals, and deliver durable tasks to agents via MCP, REST, inbox, webhook, MQTT or SSE.

GitHub

Configuration Example

{
  "name": "High-severity server alert",
  "description": "Ask my assistant what to do when a server alert comes in.",
  "trigger": {
    "signal_id": "custom.event",
    "parameters": {"topic": "server.alert"}
  },
  "condition": "payload.level == \"high\"",
  "delivery": {
    "destination_id": "<destination-id>",
    "task_type": "handle_server_alert"
  },
  "execution": {"cooldown_seconds": 300, "maximum_attempts": 5}
}

README

# Signalplane

**Give your AI agent a future tense.**

Signalplane is a small service you run yourself. It watches the world for
you — weather, earthquakes, new software releases, security warnings, prices,
Reddit posts, sports games, RSS feeds, and more — and when something you care
about happens, it hands the event to your AI agent as a task.

You write one line of logic ("tell me when it rains in Berlin"), Signalplane
does the watching, and your agent does the acting — summarizing, alerting,
updating a dashboard, whatever you decide.

```text
Signalplane watches → something happens → your agent gets a task → acts
```

## The idea in one minute

Most AI agents only know what you tell them. Signalplane gives them eyes.

- **Signals** are things that can happen: `weather.forecast.updated`, a new
  `PyPI` release, a `crates.io` release, an `OSV` security advisory, a price
  crossing, a Reddit post, an MLB game reaching a final score.
- You write a **rule**: pick a signal, set parameters (like a city or a
  package name), and add a simple condition (`payload.current.precipitation > 0`).
- Signalplane polls the source once — even if 1,000 rules ask for the same
  thing, it makes **one** check and fans the result out locally.
- When the rule matches, Signalplane creates a **task** and delivers it to
  your agent's **destination**: an inbox your agent pulls from, a webhook
  pushed to your server, an MQTT topic, or a live stream.

The exciting part: an AI assistant discovers the available signals over MCP
or REST, writes the rule for you in plain language, and you just approve it.

## What you get

- A **catalog of 21 live signals** — see [What can I watch?](#what-can-i-watch)
- **MCP server** so Claude, Copilot, and other agents can discover signals
  and manage rules over a standard protocol
- A **REST API** for everything, with an OpenAPI document
- **CEL conditions** — a small, safe expression language (no code execution,
  no network calls from rules)
- **Coalesced watches** — identical rules share one poll, not one poll per rule
- **Durable tasks** with retries, delivered to inbox / webhook / MQTT / SSE
- **Rule templates** — ready-made rules an agent can copy and adapt
- **Multi-tenant** API keys, per-tenant isolation, rate limiting, encryption
  at rest for secrets
- **Connector SDK** — write your own connector as a separate service in any
  language (never runs inside Signalplane)
- Run as a **public free service** or **inside your network**: Docker,
  Docker Compose, and a Kubernetes Helm chart

## Quick start (5 minutes)

Requirements: Docker with Compose.

```bash
# 1. Copy the example config
cp .env.example .env

# 2. Generate two secrets
openssl rand -hex 32          # put this into SIGNALPLANE_BOOTSTRAP_API_KEY
openssl rand -base64 32       # put this into SIGNALPLANE_ENCRYPTION_KEY

# 3. Start everything (Postgres is included)
docker compose up --build
```

Open [http://localhost:8080](http://localhost:8080) — you'll see the public
catalog and health page immediately. No login needed to look around.

## Try it yourself (the whole loop in ~2 minutes)

This demo uses the **custom event** signal, so you don't need to wait for
weather, earthquakes, or a release — you trigger the event yourself.

### 1. Create a tenant (your own private space)

The bootstrap key is only for setup. Use it once to create a tenant; the
response contains that tenant's administrator key **exactly once** — save it.

```bash
curl -sS http://localhost:8080/v1/admin/tenants \
  -H "Authorization: Bearer $SIGNALPLANE_BOOTSTRAP_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"slug":"demo-agent","name":"Demo agent"}'
```

```bash
export TENANT_KEY=<the token from the response>
```

### 2. Create an inbox destination (where tasks queue up)

```bash
curl -sS http://localhost:8080/v1/destinations \
  -H "Authorization: Bearer $TENANT_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"name":"My assistant","kind":"inbox"}'
```

Save the returned `id` — that's your destination.

### 3. Write a rule

A rule says: *when a custom event arrives on topic `server.alert` and the
level is high, give my agent a task.*

```json
{
  "name": "High-severity server alert",
  "description": "Ask my assistant what to do when a server alert comes in.",
  "trigger": {
    "signal_id": "custom.event",
    "parameters": {"topic": "server.alert"}
  },
  "condition": "payload.level == \"high\"",
  "delivery": {
    "destination_id": "<destination-id>",
    "task_type": "handle_server_alert"
  },
  "execution": {"cooldown_seconds": 300, "maximum_attempts": 5}
}
```

```bash
curl -sS http://localhost:8080/v1/rules \
  -H "Authorization: Bearer $TENANT_KEY" \
  -H 'Content-Type: application/json' \
  -d @rule.json
```

### 4. Activate the rule

Drafting and activating are separate steps on purpose: the assistant can
prepare a rule, you check it, then you authorize it to run.

```bash
curl -sS -X POST http://localhost:8080/v1/rules/<rule-id>/activate \
  -H "Authorization: Bearer $TENANT_KEY"
```

### 5. Make the event happen

```bash
curl -sS -X POST http://localhost:8080/v1/events/custom/server.alert \
  -H "Authorization: Bearer $TENANT_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"payload":{"level":"high","message":"disk at 97%"}}'
```

### 6. Watch the task appear — and complete it

```bash
curl -sS http://localhost:8080/v1/tasks/claim \
  -H "Authorization: Bearer $TENANT_KEY" \
  -H 'Content-Type: application/json' \
  -d "{\"destination_id\":\"<destination-id>\",\"limit\":10}"
```

```bash
curl -sS -X POST http://localhost:8080/v1/tasks/<task-id>/complete \
  -H "Authorization: Bearer $TENANT_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"result":{"ok":true,"note":"notified on-call"}}'
```

That's the whole model: **event → rule → task → agent**. Everything else is
scale, security, and convenience.

## What can I watch?

Some signals ship out of the box; more are added over time (each one lives in
`connectors/builtin/` and follows a strict review checklist). Browse them
live at `GET /v1/catalog/signals` or over [MCP](#mcp).

| Signal | Description | Example rule |
|---|---|---|
| `weather.forecast.updated` | Detailed forecast for any location | "Tell me when it rains in Berlin" |
| `air_quality.forecast.updated` | Air-quality forecast for a location | "Warn me when air is unhealthy" |
| `astronomy.sunset` | Exact sunset for a location (no polling!) | "Brief me every evening at sunset" |
| `earthquake.detected` / `weather.alert` / `river.streamflow` | Earthquakes, alerts, river levels | "Alert me on earthquake > 5.0 near me" |
| `market.price_threshold` | Crypto price crossing | "Notify me when BTC crosses $100k" |
| `market.quote_threshold` | Equity / index / FX quote crossing | "Rebalance when GOOG drops below $X" |
| `pypi.package.new_version` | New Python package release | "Summarize new versions of my dep" |
| `npm.package.new_version` | New npm package release | "Tell me when Express releases" |
| `crates.package.new_version` | New Rust crate release | "Watch serde for new versions" |
| `security.osv.vulnerability` | New OSV security advisory | "Alert me on critical CVEs for my stack" |
| `hackernews.story` | Hacker News front-page stories | "Brief me on strong AI posts" |
| `social.reddit_post` | Reddit posts matching keywords | "Brief me on every DDoS post in r/netsec" |
| `sports.mlb_score` / `sports.mlb_team_final` | MLB game milestones | "Tell me when the Yankees game is final" |
| `transit.gtfs_realtime.entity.updated` | GTFS-Realtime transit alerts | "Warn me about delays on my line" |
| `calendar.holiday` | Upcoming public holidays | "Plan around Easter weekend" |
| `http.json.changed` | Any public JSON API | "Watch this API for changes" |
| `rss.item.published` | Any RSS/Atom feed | "Digest new posts from my blog list" |
| `custom.event` | Your own webhook events (tenant-private) | "Route my CI alerts" |

Each signal publishes its **parameter schema and payload schema**, so an
agent can learn exactly what to send and what it will receive — no guessing.

## Rule templates

`catalog/rules/templates/` (also exposed at `GET /v1/catalog/rule-templates`)
has ready-made rules — destination-free, so an agent fills in its own
destination and parameters. Examples:

- `weather-rain-now` — it rains at your location
- `weather-severe-alert` — severe weather warning
- `market-price-crossed` — a crypto price crosses a threshold
- `software-pypi-release` — a Python package releases a new version
- `security-new-vulnerability` — a critical advisory for an ecosystem
- `social-reddit-keyword-post`, `sports-mlb-game-final`, and more

## MCP

Connect any MCP-compatible assistant (Claude, Copilot, Cursor, …) to:

```text
http://localhost:8080/mcp
```

with your bearer token in the transport's `Authorization` header. The MCP
server exposes tools to:

- **discover** signals and rule templates (`signals_list`, `rule_templates_list`)
- **manage** destinations, rules, and activation (`destinations_create_inbox`,
  `rules_validate`, `rules_create`, `rules_activate`, `rules_pause`)
- **consume** work (`tasks_claim`, `tasks_complete`)
- **administer** connectors (system administrators only)

The `signalplane://catalog` and `signalplane://rule-templates` resources give
agents the full signal catalog, schemas, and ready-made rules.

## Where tasks go

Every rule delivers to one destination:

| Kind | Model | When to use |
|---|---|---|
| `inbox` | Your agent pulls tasks (`tasks_claim`) | Interactive agents; the default |
| `webhook` | Signalplane POSTs a signed task to your URL | Your server is reachable |
| `mqtt` | Signalplane publishes to a broker topic (QoS 1) | Home automation, broker-native agents |
| SSE stream | Push over server-sent events with one-use tickets | Browsers and subscribers that can't receive HTTP POSTs |

Webhook deliveries are HMAC-SHA256 signed with a shared secret
(`X-Webhook-Signature-V2`, `X-Webhook-Timestamp`, `Id

... (truncated)
tools

Comments

Sign in to leave a comment

Loading comments...