Watches

Tell Pepe to keep an eye on something and warn you the moment it happens. It checks on its own, survives restarts, and notifies you exactly once.

Watches

A watch answers a different question: not “do this on a clock” but “keep an eye on something and tell me the moment it happens.” A watch re-checks a condition on a timer and notifies you once when it becomes true, then stops. It is durable: it survives a restart and the closing of the session that created it, and it always replies on the channel it was created from.

Probe versus agent triggers

The cheap part of a watch is the trigger, which runs on every interval. Only when the trigger fires does the (possibly expensive) notification run, once. There are two kinds of trigger:

Because agent checks cost tokens, their minimum interval is higher: 300 seconds for agent triggers, 30 seconds for probes. The default interval is 120 seconds.

What it sends when it fires

When the trigger finally passes, a watch delivers a message. That message is either a fixed template (a piece of text you set up front, no model call), or composed by the agent at fire time (one model call, once) so it can include fresh detail like a summary of what actually happened.

The combination worth knowing is a free probe gating an agent-composed message. The curl polling costs nothing, and the model is only asked to write the summary at the moment the condition passes.

Create a watch from the CLI

The CLI creates probe watches. Agent-judged watches are created from chat, where the model is already in the loop.

pepe watch add "api-up" \
  --probe "curl -sf https://api.example.com/health" \
  --message "The API is back up." \
  --every 120 \
  --deliver "telegram:123456789"

Managing watches:

pepe watch list                 # all watches, with state and check count
pepe watch pause api-up
pepe watch resume api-up
pepe watch cancel api-up

Do it in the dashboard

Open the Watches page under pepe serve to see every watch with its state, trigger, interval, and how many checks it has used against its budget. From there you can pause, resume, and cancel a watch. New watches are created from the CLI or by chat, where the trigger and delivery target are set up.

Do it by chat

Ask in plain language and the agent creates the watch through its watch tool. Like schedule_task, the watch tool comes enabled by default (remove it from an agent’s tools if it should never create one) and still goes through the same permission prompt on each create.

Let me know when the deploy finishes. Check every few minutes.

For a scriptable check the agent sets up a probe. For something that needs judgement it sets up an agent trigger, phrasing a yes/no question it answers each interval. It can also choose to compose the fire message with the model instead of a fixed template, so the notification carries a real summary rather than a canned line. The watch tool’s actions are create, list, pause, resume, and cancel.

To keep things bounded, at most 50 watches can be active at once, and Pepe refuses a new watch whose condition is identical to one already running, so you cannot accidentally stack duplicates. A watch also has a maximum number of checks; if the condition never comes true within that budget, the watch expires quietly instead of polling forever.

Delivery to the origin channel

A watch records its origin, the channel and conversation it was created from, at creation time. When it fires it delivers back there, even after a restart, whether that is a Telegram chat (a direct push), a connected terminal or WebSocket session, or the application log. On a WebSocket the notification arrives as a "watch" event on the channel; pass a stable session when you join and you will receive it across reconnects, instead of only on the socket that happened to create the watch. In pepe chat it is printed inline in the console. If the watch was created over the stateless HTTP API (which has no conversation to message back), it falls back to the log.

Two guarantees make this reliable:

A watch moves through a small set of states over its life: pending (still watching), paused, done (fired and delivered), expired (ran out of its check budget), or cancelled.

No database to install, no crontab. Scheduled tasks stay as plain records in ~/.pepe/config.json (under "crons"), with one JSONL run-history file per task under <PEPE_HOME>/data/cron_logs/. Watches live in the same small embedded SQLite file as commitments, not something you need to install or manage yourself. Either way, there is nothing else to keep running: the whole scheduler is an in-process timer that runs on whichever long-lived surface is up, pepe serve, a gateway, or an interactive pepe chat, and stops when you stop it. Run only one of them at a time against the same config: two would both tick, and a watch would fire twice.