# Scheduled Watchers

> Cron-style subagents that periodically check on your deployed strategies. Built around a material-change gate so you only hear from them when something actually moved.

Source: https://finnyai.tech/docs/watchers

## Creating a watcher

The `schedule_subagent` tool creates a watcher with:

- **Cron expression**: 5-field, or a market alias like `@market-open`.
- **Recurring**: auto-expires after 7 days unless explicitly extended.
- **Durable**: survives Scout restarts.
- **Custom notes**: e.g. *alert if drawdown exceeds 5%*.

## The evaluation cycle

The scheduler ticks every 60 seconds. For each matching job:

1. **Snapshot**: `WatcherEvaluator` fetches a live market snapshot, price, account equity, position qty, and compares it to the last baseline.
2. **Gate**: Only triggers a full agent run if a **material change** is detected (≥2% price/equity move, or a position flip). First tick captures the baseline and skips.
3. **Run**: On material change, `PromptRunner` spins up the watcher agent with market context attached.
4. **Deliver**: Any response other than `"No change."` is routed back to the parent session by the `Inject` service.

## Delivery

The Inject service watches session status on the bus and routes findings accordingly:

- **Idle session** → delivered immediately via the SDK `promptAsync`.
- **Busy session** → queued, flushed when the session goes idle.
- **Session gone** → falls back to an OS notification, rate-limited to 1/hour per watcher.

Queued findings expire after 24h. A watcher that fails 5 times in a row auto-pauses.

## Observability

Every state transition emits an analytics event to Convex:

```
watcher.fired_material
watcher.delivered
watcher.fallback_notified
watcher.auto_paused
watcher.expired
```

> **Why the material-change gate**: Naive cron-driven LLM runs are expensive and noisy. A 5-minute watcher that triggers a full agent every tick burns tokens describing nothing. The gate keeps cost proportional to what actually changed in the market.

## Listing and managing watchers

Use the schedule-subagent tooling to `list`, `update`, or `pause` existing watchers. The scheduler reloads its job table on each tick, so changes take effect within ~60 seconds.
