Sentinel agent
packages/sdk/examples/sentinel-bot.ts posts uptime incidents from
Sentinel into a channel. It is the shape most
useful integrations take: a deterministic event, formatted well, in the right
room.
There is no model in it. Sentinel already knows what is down. Asking an LLM to restate that would add latency, cost, and a chance of being wrong about a fact it was handed. Add a model when you want to ask things (“what has been flapping this week?”), not to relay them.
Running it
Section titled “Running it”SLICK_URL=https://chat.example.com SLICK_TOKEN=slk_… \SLICK_CHANNEL=01J… \SENTINEL_URL=https://sentinel.rootstuff.io SENTINEL_TOKEN=… \ pnpm --filter @slick/sdk exec tsx examples/sentinel-bot.tsWithout SLICK_CHANNEL it looks for #ops, #alerts, #incidents, then
#general, so the common case needs no id.
What it posts
Section titled “What it posts”sentinelwww.modwash.com is downHTTP 504 - Could not fetch page contentstarted 21:53 UTC · incident 9001 └ 1 replyThe recovery goes in the thread, not the channel. One incident, one thread, so the channel stays a list of events rather than a stream of noise.
The setting that makes it usable
Section titled “The setting that makes it usable”Real monitoring data is full of incidents that open and close inside a minute: a 504 that clears on the next check, one SSL handshake that times out. Posting each one turns the channel into noise, and a noisy channel gets muted, which costs you the alert that mattered.
So a new incident is held for MIN_DURATION_SECONDS (default 60) before it
is announced. If it resolves first, nobody hears about it. Set it to 0 to
announce everything.
Polling or webhook
Section titled “Polling or webhook”| Variable | Default | Meaning |
|---|---|---|
POLL_SECONDS |
30 |
How often to ask Sentinel for ongoing incidents |
PORT |
unset | Set it to also accept webhook POSTs |
SENTINEL_WEBHOOK_SECRET |
unset | HMAC-SHA256 over the raw body, compared in constant time |
MIN_DURATION_SECONDS |
60 |
Flap suppression, above |
SENTINEL_STATE |
./.sentinel-bot-state.json |
Which incidents have been announced |
Polling is the default because it needs no inbound connectivity, and a self-hosted bot is usually behind NAT with no public URL. Webhooks are faster if you can expose a port.
The state file is what stops a restart reposting last week’s outages, and what lets a recovery find its thread. Keep it on a volume that survives restarts.
Writing your own
Section titled “Writing your own”This is a template more than a product. The pattern transfers to anything with an API and events worth hearing about: poll or receive, suppress the noise, post once, reply in the thread. See Bots and agents for the API it is built on.