Raw feeds are too literal.
Subscribing to raw events is easy. Deciding which combinations actually matter is the hard part. Agents still end up reading noisy feeds and rebuilding the same logic again and again.
events.on("Transfer", notify)events.on("Borrow", notify)events.on("Liquidate", notify)events.on("Redeem", notify) // Raw event streams.// Too much activity, not enough intent.Use DSL to state what you mean.
The useful abstraction is a DSL that describes the actual state change you care about: specific scope, exact thresholds, time windows, and logic gates. That gives your agent a signal instead of a feed.
{ "scope": { "chains": [1], "protocol": "all" }, "conditions": [ { "metric": "Price.deviationBps", "operator": "<=", "value": -10 }, { "metric": "Liquidity.availableUsd", "operator": "<", "value": 5000000 } ], "logic": "AND", "window": { "duration": "2h" }}Write intent. Rely on the infrastructure.
Your agent can use DSL to describe exactly what it wants, while Sentinel handles the hard part: continuous evaluation, stateful windows, logic composition, and reliable delivery. That keeps the signal definition precise without making the production path fragile.
POST /api/v1/signals{ "name": "3 of 5 Morpho vault exits", "definition": { "scope": { "chains": [1], "markets": ["0x..."], "protocol": "morpho" }, "conditions": [ { "type": "group", "addresses": ["0x1...", "0x2...", "0x3...", "0x4...", "0x5..."], "requirement": { "count": 3, "of": 5 }, "conditions": [ { "type": "change", "metric": "Morpho.Position.supplyShares", "direction": "decrease", "by": { "percent": 20 }, "window": { "duration": "1d" } } ] } ], "logic": "AND", "window": { "duration": "7d" } }, "notify": ["telegram", "webhook"]}