Skip to main content

kitsdeals-river

Python SDK for consuming the Kit's Deals river — a real-time, structured stream of approved deals built for agent consumers.

The interaction model is agent-mediated. You're not expected to edit YAML by hand. You tell your Claude/Code agent something like "set up github.com/kitsdeals/kitsdeals-river for me — I'm looking for TVs and a laptop refresh", and the agent runs the onboarding skill (PR 37) to translate the conversation into a ~/.kitsdeals/profile.yaml plus a running watcher daemon. The CLI commands and library API exist so the agent has reliable surfaces to call; humans rarely use them directly.

Architecture

┌──────────────────────────────────────────────────────────────────┐
│  RiverWatcher                                                    │
│    SSE consumer (Kit's Deals river v2)                           │
│    ↓                                                             │
│    Reconnect with exponential backoff                            │
│    Cursor persistence (~/.kitsdeals/cursor.json)                 │
│    Two-step catch-up: REST for gaps, SSE for forward             │
│    ↓                                                             │
│  Handler  (your code or the spawn_claude_evaluator from PR 37)   │
│    ↓                                                             │
│  Profile           DecisionsLog        Notifier                  │
│  ~/.kitsdeals/     ~/.kitsdeals/       telegram / stdout / …     │
│   profile.yaml      decisions.jsonl                              │
└──────────────────────────────────────────────────────────────────┘

Status

Component Status
RiverWatcher — SSE + reconnect + cursor + filter + SIGHUP reload ✓
Profile — Pydantic schema, YAML load/save, dedup helpers ✓
DecisionsLog — JSONL append-only with size-based rotation ✓
Notifier — protocol + 6 built-ins (stdout, telegram, slack, discord, http_post, subprocess) ✓
spawn_evaluator — agent-agnostic wake-up with structured prompt ✓
skills/onboarding.md — agent-facing setup interview ✓
skills/update-profile.md — agent-facing ongoing refinement ✓
CLI (setup, run, reload, status, profile show/update/validate) ✓
Server-side GET /v1/quickstart agent funnel ✓
examples/kit_dual_emit.py — reference dual-emit pattern (observability + agent action) ✓

Install

pip install kitsdeals-river

(Pre-publish: pip install -e . from this directory.)

Agent-driven setup (the expected install flow)

Paste this repo URL to your Claude Code agent and say:

Set up Kit's Deals for me — I'm looking for X and Y.

The agent loads skills/onboarding.md, runs a short interview (4–6 questions max), translates your answers to a profile, and starts the watcher. You don't see the YAML.

For ongoing changes — "stop showing me TVs", "I bought one of those", "only show me clear wins" — your agent loads skills/update-profile.md and translates the natural-language request into a structured CLI edit. Live reload via SIGHUP, no restart required.

CLI

The CLI is the agent-facing API to the profile and the watcher daemon. Humans rarely run these directly; the skills tell the agent how to use them.

kitsdeals-river setup --json '<full profile JSON>'      # write profile to disk
kitsdeals-river run                                     # foreground watcher (start here, or via systemd)
kitsdeals-river run --initial-backfill                  # also surface currently-live matching deals on first start
kitsdeals-river status                                  # daemon health snapshot
kitsdeals-river reload                                  # SIGHUP a running watcher
kitsdeals-river profile show [--json]                   # inspect current profile
kitsdeals-river profile update --remove-watch "TVs"     # programmatic edits
kitsdeals-river profile validate                        # well-formedness check

setup writes the profile only — it does not start the watcher. run (or a systemd unit invoking run) is what actually opens the SSE connection. Treat them as separate concerns: one configures, the other keeps the daemon alive.

See skills/onboarding.md and skills/update-profile.md for the agent- facing recipes.

Multiple watches

Profiles can declare multiple watches (profile.watches[]). When more than one is present, kitsdeals-river run opens one SSE connection per watch concurrently in a single process — each with its own filter, its own cursor file (<cursor>-<sanitized-label>.json), and its own notify_threshold. A deal that matches multiple watches is delivered on each matching connection; the default handler dedupes by deal id and routes to the first matching watch's threshold.

Notify thresholds

Each watch declares a notify_threshold ∈ {anything, good, clear_win} that gates which matched deals actually fire a notification. Mapping against the server's deal-quality score (deal_score, 0–100):

threshold floor when to use
anything none — every match notifies broad watches you actively want noisy
good deal_score ≥ 60 typical default; filters out obvious lemons
clear_win deal_score ≥ 80 only-the-best alerts; lots will be filtered

Deals lacking deal_score only notify when notify_threshold is anything — refuse-to-guess posture.

Telegram delivery setup

The default notifier reads TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID from the environment. Two prerequisites:

  1. Create a bot via Telegram's @BotFather: send /newbot, pick a display name and username, save the token BotFather replies with.
  2. The user must DM the bot first. Telegram bots cannot send the first message — the user has to open a chat with their new bot and send /start (or any message). Skip this step and the watcher runs fine but sendMessage returns Forbidden: bot can't initiate conversation with a user.

Then retrieve the chat_id (GET https://api.telegram.org/bot<TOKEN>/getUpdates returns result[*].message.chat.id) and put both values in the environment file your service reads. For full step-by-step including verification and forum-topic routing, see skills/onboarding.md — the agent-facing version walks through every failure mode.

The default notification format includes brand, product name, current

  • original price, discount %, merchant, condition, deal score, optional quality verdict, the product URL (Telegram unfurls into a card), and an expiry countdown when known.

Minimal example (without an agent in the loop)

from kitsdeals_river import RiverWatcher, RiverEvent, StdoutNotifier
from kitsdeals_river.profile import WatchFilter
import asyncio

async def main():
    notifier = StdoutNotifier()
    watcher = RiverWatcher(
        filter=WatchFilter(
            category="tv",
            brand_in=["LG", "Sony"],
            min_discount_pct=25,
        ),
    )

    @watcher.on_event
    async def handle(event: RiverEvent):
        if event.is_deal:
            deal = event.data
            await notifier.send(
                f"{deal['brand']} — ${deal['current_price_cents']/100:.2f}",
                deal,
            )

    await watcher.run_async()

asyncio.run(main())

See examples/minimal.py for a runnable version.

Testing

pip install -e ".[dev]"
pytest

License

MIT — see LICENSE. Use freely, build on top, fork it for your own personal-event runtime.

Roadmap

This package is one channel of a broader pattern: decoupled summarization — a centralized service does expensive synthesis work once, emits a structured event stream, and agents do cheap per-event filtering against a user profile. Same architecture applies to news, jobs, regulatory filings, GitHub releases, real-estate listings. Kit's Deals is the first concrete implementation; the SDK's profile + watcher + decisions-log shapes are designed to translate.

Metadata

Release files for kitsdeals-river 0.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for kitsdeals-river 0.4.1
File Size Uploaded Provenance
kitsdeals_river-0.4.1.tar.gz 54.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for kitsdeals-river 0.4.1
File Interpreter ABI Platform
kitsdeals_river-0.4.1-py3-none-any.whl Python 3 none any Details

Total release size: 99.6 kB

Release files / kitsdeals_river-0.4.1.tar.gz

Download URL kitsdeals_river-0.4.1.tar.gz
Size 54.9 kB
Tags Source
SHA-256 checksum
How to use checksums
e812fd9043ff0d5457ce90620df0f9bd7644f0ee827fb553e7168477f06f78b8
BLAKE2b-256 checksum
How to use checksums
6ed9eb18859f0cf66e27dd37f60a920cd7904a36bdfba13c0356db7edc0f8170
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.15

Release files / kitsdeals_river-0.4.1-py3-none-any.whl

Download URL kitsdeals_river-0.4.1-py3-none-any.whl
Size 44.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e1e0a3adc779c3187879fa1316b0d2fd45fce9c6af4a6ae5e9d7bd9fb1626b77
BLAKE2b-256 checksum
How to use checksums
0c83c4a86a5cb0cbf2958eb5b0d90a7311332d23e043bb43c1e75a2ec058d42a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.15

Security for kitsdeals-river 0.4.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page