DeepSeek Harness Plugin

shangjian2023/dsh-rss-daily

Stars ★ 2 Downloads (30d) 1,394 Category Notifications & Integrations Added 2026-08-24 npm dsh-rss-daily

Daily news digest from 46 curated RSS sources, edited by the model already configured in dsh, delivered to your IM via webhook, and broadcast in the chat like a regular model reply with zero context cost.

Install

# from npm (prebuilt)

dsh plugin --profile web add dsh-rss-daily

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:shangjian2023/dsh-rss-daily

Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).

README

One line: every morning, dsh quietly prepares an editor-grade news digest for you — curated from 46 RSS sources by the model you already configured, delivered to your IM, and broadcast in the chat like a regular reply (zero context cost).

中文说明

CI

What it looks like

The digest shows up inside your conversation, styled exactly like a model reply — plain markdown, same typography, same width:

In-chat digest

It's frontend-only: displayed in the chat, but never written to the session log and never sent to the model. Your context stays clean.

Why you'll like it

  • It reads like an editor picked it, not an aggregator. ~20 candidates are scored (source tier × recency × signal words), deduplicated (Jaccard + 14-day MD5 history), cross-checked against a multi-source event graph, then handed to your own dsh model for the final edit: merge same-event reports, drop PR filler, balance topics (max 2 per tag), and compress each item into one concrete fact line (≤45 chars).
  • Zero extra API keys. The editorial pass goes through ctx.llm — whatever model your dsh already runs. No new credentials, no extra bill.
  • It never misses a day. If the model call fails, the digest degrades to a deterministic rule-based selection automatically. If dsh was down at the scheduled time, it catches up on next boot (within 12 h).
  • It comes to you. Webhook delivery to ServerChan / PushDeer / WeCom / Telegram / Bark / gotify / any custom endpoint. At least one success counts as delivered.
  • Production-grade pipeline. Ported from a personal script that has run daily since June 2026 through 9 revisions: per-source health tracking with adaptive timeouts, feed mojibake repair, full-text enrichment for thin summaries, a 420 s hard budget (SIGALRM on POSIX; on Windows via per-request timeouts plus soft budget checks), and idempotent two-phase send (fetch → outbox → deliver → confirm).

Quick start

# from npm (recommended)
dsh plugin --profile web add dsh-rss-daily

# or from GitHub
dsh plugin --profile web add github:shangjian2023/dsh-rss-daily

Restart dsh web. Every conversation header gets a 📰 button, and the daily schedule is live.

30-second setup:

  1. Click the 📰 button in any conversation → Settings tab
  2. Pick a time and add a delivery target (ServerChan / PushDeer / WeCom / Telegram / Bark / gotify / custom webhook)
  3. Hit Get today's digest — the digest is generated right now, delivered to your webhook, and appears in the chat

No YAML editing required — everything (schedule, targets, sources, digest size, LLM provider) is editable in the panel and takes effect immediately.

Highlights

  • 🖥 Three UIs, zero context cost: the in-chat broadcast, the 📰 panel (digest / sources / settings), and the plugin settings card — all rendered client-side, never entering the session log

  • 📝 The broadcast is a real-looking reply: the digest body renders through the host's own MarkdownText component (the exact component behind genuine assistant messages), streams in with a typing cadence, and hides its action row until done — it looks like the model answering, yet costs zero context tokens

  • 🧰 46 curated sources across AI / tech / science / world / finance / dev / humanities and 15 categories in total, reachability-tested from mainland China; add or disable your own in the sources tab (sources failing 3 times in a row auto-degrade for 24 h; recovery needs 2 consecutive successes)

  • 🤖 rss_daily agent tool — run / status / redo / deliver, so you can also just ask the agent "generate today's news digest"

  • 🔌 Headless mode — py/daily.py runs standalone with any OpenAI-compatible endpoint, no dsh required:

    RSS_LLM_ENDPOINT=https://api.deepseek.com/v1 RSS_LLM_KEY=sk-... \
      python py/daily.py --state-dir ~/.rss-daily
    

Configuration

Defaults are sensible; the panel covers everything. The main knobs:

Key Default Meaning
time 08:00 Local HH:MM to run daily (boot catch-up if missed <12 h). The digest title date is computed in Beijing time (UTC+8)
targets[] [] Delivery targets; delivered = at least one succeeded
digestItems 8 Max items per digest
llmMode harness harness (use dsh's model) or none (rule-based only)
broadcast true Show the in-chat digest card
stateDir ~/.dsh/rss-daily Sources / dedup history / outbox live here

Power users can also overlay the config row in the profile's cordis.patch.yml; see the HTTP API and pipeline stages docs for the full surface.

How it works

46 sources ──▶ fetch (health, timeouts, dedup) ──▶ ~20 candidates
                                                       │
                              ctx.llm editorial pass (rule fallback)
                                                       │
                                    digest ──▶ webhook targets ──▶ confirm
                                                       │
                              in-chat broadcast (frontend-only)

py/daily.py is independently scriptable (--stage fetch|finalize|confirm|status, single-line JSON on stdout); the plugin drives exactly these stages. Never confirms before at least one delivery succeeds — confirmed items enter the 14-day dedup window permanently.

The editorial prompt suite is distilled from AIHOT (an open-source self-curating hot-news framework): five-axis private scoring with a noise-suppression table, answer-first one-liners, self-contained titles, anti-hallucination rules, an optional day lead, and per-event corroboration badges (✚N outlets). Selection may fall back to rules, but the digest language never does: a translate-only salvage pass runs before raw titles are shown (and those carry an explicit "raw titles" note).

DSH Desktop compatible: the default model follows the host's agentDefaultModel selection; empty replies (thinking models burning the token budget on reasoning) retry once at doubled budget; every paid call is receipted with a daily budget breaker; the panel ships its own opaque light/dark design system (host CSS variables renamed in 0.2.0-rc once left it transparent); without a host settings service, panel config persists to stateDir/panel-config.json.

MCP (for other agents)

mcp/server.py exposes the same pipeline as MCP tools, so Claude Code, Codex, opencode, Cursor — any MCP client — can drive it: rss_status, rss_fetch, rss_finalize, rss_confirm. The host agent acts as both the editor (pick & rewrite per the returned prompt) and the delivery channel (show the digest to the user).

The state directory is shared with the dsh plugin by default (idempotency and fetch locking honored across both); scheduled delivery stays with the dsh plugin or cron — MCP is for interactive use.

One-liner for Claude Code (user scope, all projects):

claude mcp add --scope user rss-daily -- python /path/to/dsh-rss-daily/mcp/server.py

See mcp/README.md for Codex / opencode configs and the long-task polling convention.

Requirements

  • dsh with the web (or any long-running) profile
  • Python 3.9+ with feedparser (pip install feedparser); add pip install mcp for the MCP server (both mcp 1.x and 2.x work)
  • Node.js ≥ 22.19 (matches the dsh host's own Node requirement; the plain-JS layers stay 18-compatible, but the plugin only runs inside dsh)

License

MIT

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →

Community comments

Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.