feat(watchlist): implement delivery webhook dispatch#86
feat(watchlist): implement delivery webhook dispatch#86hnshah wants to merge 1 commit intomvanhorn:mainfrom
Conversation
Completes the delivery layer that was scaffolded but never implemented.
Config commands existed but findings were never actually delivered.
## Problem
`watchlist config delivery` writes to settings table but `_run_topic()`
never reads the config or sends notifications. Research runs silently,
findings accumulate in SQLite, nothing comes out.
## Impact
- Watchlist is designed for always-on AI environments
- Without delivery, research findings sit in DB with no notification
- Users must manually check briefings instead of being notified
## Changes
**Added delivery functions:**
- `_deliver_findings()` - Reads config, checks conditions, dispatches
- `_format_delivery_message()` - Formats announce/silent/default modes
- `_send_slack_webhook()` - POST to Slack incoming webhooks
- `_send_generic_webhook()` - POST JSON to generic https:// URLs
**Delivery conditions:**
- Only sends when `delivery_channel` is configured
- Only sends when `counts['new'] > 0`
- Errors are logged but don't block research
**Message modes:**
- `announce` (default): "📰 *last30days update: {topic}* 3 new, 1 updated"
- `silent`: "last30days: 3 new findings for 'topic'"
- `default`: "last30days: Research complete for 'topic'"
**Config validation:**
- Updated `cmd_config()` to validate delivery URLs (must be https://)
- Empty string disables delivery
- Returns status: enabled/disabled
**Integration point:**
- Called in `_run_topic()` after `store.update_run(..., status='completed')`
- Happens AFTER findings are stored (delivery is non-blocking)
## Testing
- 8 unit tests covering all delivery paths
- Message formatting verified (announce/silent modes)
- Slack webhook POST format validated
- Generic webhook POST format validated
- No-op conditions tested (empty channel, zero new)
- Error handling confirmed (failures don't propagate)
## Future Enhancements
Webhook dispatch is generic enough to support:
- Telegram (via bot API endpoint)
- Discord (via webhook URL)
- Email (via HTTP gateway)
- Custom integrations (any https:// endpoint)
Current implementation focuses on webhooks as the universal primitive.
## Usage
```bash
# Configure Slack webhook
last30 config delivery https://hooks.slack.com/services/T/B/xxx
# Configure generic webhook
last30 config delivery https://myserver.com/last30days-hook
# Disable delivery
last30 config delivery ""
# Set delivery mode (optional, default: announce)
# (delivery_mode setting already exists in schema)
```
|
This is the missing piece for always-on research. I'm building autonomous agents that need to surface research findings proactively (morning briefs, pre-outreach intel). Without delivery, watchlist is a write-only database. The webhook dispatch makes it composable with other systems. Big +1. |
|
Hey Hiten, wanted to loop back on all three PRs. The watchlist improvements - webhook dispatch here, HN/Polymarket storage (#85), and the scanning window extension (#84) - all look promising. As I mentioned on #84, there's a bigger release coming that's going to change a lot of the internals. I can't commit to merging any of these right now, but I promise I'll consider each one once 3.0 lands and ping you to rebase if needed. Thanks for being patient with the process. |
Completes the delivery layer that was scaffolded but never implemented.
Problem
watchlist config deliverywrites to settings table but_run_topic()never reads the config or sends notifications. Research runs silently, findings accumulate in SQLite, nothing comes out.Impact
Changes
Added delivery functions:
_deliver_findings()- Reads config, checks conditions, dispatches_format_delivery_message()- Formats announce/silent/default modes_send_slack_webhook()- POST to Slack incoming webhooks_send_generic_webhook()- POST JSON to generic https:// URLsDelivery conditions:
delivery_channelis configuredcounts['new'] > 0Message modes:
announce(default): "📰 last30days update: {topic} 3 new, 1 updated"silent: "last30days: 3 new findings for 'topic'"default: "last30days: Research complete for 'topic'"Config validation:
cmd_config()to validate delivery URLs (must be https://)Testing
Future Enhancements
Webhook dispatch is generic enough to support:
Usage
Completes Issue #1 from Oatis's fix spec! 🎯