RSS feed aggregator, deduplication engine, LLM scoring, and output dispatcher for OpenClaw agents. Use when: fetching recent articles from configured sources, filtering already-seen URLs, deduplicating by topic, scoring with LLM, dispatching digests to Telegram/email/Nextcloud/file. Enhanced by mail-client (email output) and nextcloud-files (cloud storage).
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
RSS feed aggregator, deduplication engine, LLM scoring, and output dispatcher for OpenClaw agents. Use when: fetching recent articles from configured sources, filtering already-seen URLs, deduplicating by topic, scoring with LLM, dispatching digests to Telegram/email/Nextcloud/file. Enhanced by mail-client (email output) and nextcloud-files (cloud storage).
homepage
https://github.com/Rwx-G/openclaw-skill-veille
compatibility
Python 3.9+ - no external dependencies (stdlib only) - network access to RSS feeds
RSS feed aggregator with URL deduplication and topic-based deduplication for OpenClaw agents.
Fetches articles from 20+ configured sources, filters already-seen URLs (TTL 14 days),
and deduplicates articles covering the same story using Jaccard similarity + named entities.
No external dependencies: stdlib Python only (urllib, xml.etree, email.utils).
Credentials are only used if you enable the corresponding output. None are required for core functionality (RSS fetch + dedup).
Output
Credential source
What is used
telegram_bot
~/.openclaw/openclaw.json or bot_token in output config
Bot token (read-only)
mail-client
Delegated to mail-client skill (its own creds)
Nothing read directly
mail-client (SMTP fallback)
smtp_user / smtp_pass in output config
SMTP login
nextcloud
Delegated to nextcloud-files skill (its own creds)
Nothing read directly
Cleanup on uninstall
python3 scripts/setup.py --cleanup
Security model
Credential isolation
API keys are read from dedicated files (default ~/.openclaw/secrets/), never from config.json. The scorer warns at runtime if a key file has overly permissive filesystem permissions.
SMTP credentials (fallback only) are stored in the output config block — use the mail-client skill delegation to avoid storing SMTP passwords.
Subprocess boundaries
Dispatch delegates to other OpenClaw skills via subprocess.run() (never shell=True). Script paths are validated to reside under ~/.openclaw/workspace/skills/ before execution, preventing path traversal.
No credentials are passed as subprocess arguments — each skill manages its own authentication.
File output safety
The file output type validates the target path before writing: only ~/.openclaw/ is allowed by default. Additional directories can be whitelisted via config.security.allowed_output_dirs. Sensitive paths (.ssh, .gnupg, /etc/, .bashrc, etc.) are always blocked regardless of allowlist.
Written content is checked for suspicious patterns (shell shebangs, SSH keys, PGP blocks, code injection) and size-limited to 1 MB.
Cross-config reads
The only cross-config file read is ~/.openclaw/openclaw.json for the Telegram bot token, and only when telegram_bot output is enabled without an explicit bot_token. This read is logged to stderr. Set bot_token in the output config to eliminate this read entirely.
Autonomous dispatch
When scheduled (cron), the skill can send messages/files to configured outputs without user interaction. All dispatch actions are logged to stderr with an audit summary. Use enabled: false on any output to disable it without removing its config.
Shows URL seen store statistics (count, TTL, file path).
topic-stats
python3 veille.py topic-stats
Shows topic deduplication store statistics.
mark-seen
python3 veille.py mark-seen URL [URL ...]
Marks one or more URLs as already seen (prevents them from appearing in future fetches with --filter-seen).
score
python3 veille.py score [--dry-run]
Reads a digest JSON from stdin (output of fetch) and scores articles using an OpenAI-compatible LLM.
Returns enriched JSON with scored, ghost_picks, and per-article score/reason fields.
Options:
--dry-run : print summary on stderr without calling the LLM API
When llm.enabled is false (default), articles pass through unchanged ("scored": false).
Reads a digest JSON from stdin and dispatches to all enabled outputs configured in config.json.
Accepts both raw fetch output (articles key) and LLM-processed digests (categories key).
telegram_bot: bot token auto-read from OpenClaw config - no extra setup if Telegram already configured.
mail-client: delegates to mail-client skill if installed, falls back to raw SMTP config.
nextcloud: delegates to nextcloud-files skill if installed (append mode by default with date separator).
file: writes digest to a local file. Path must be under ~/.openclaw/ (default) or a directory listed in config.security.allowed_output_dirs. Sensitive paths and suspicious content are blocked (see Security model).
Configure outputs interactively:
python3 scripts/setup.py --manage-outputs
config
python3 veille.py config
Prints the active configuration (no secrets).
LLM scoring configuration
The llm key in config.json controls the optional LLM-based article scoring:
Score threshold for ghost_picks (blog-worthy articles)
Scoring rules:
Only the first top_n articles are sent to the LLM. Articles beyond top_n
are excluded from the digest entirely. fetch returns articles sorted by date
desc, so top_n selects the most recent ones. Increase top_n to evaluate
more articles per run (higher token cost).
Score >= ghost_threshold : added to ghost_picks list
Score >= 3 : kept in articles list
Score <= 2 : excluded from output
Articles are sorted by score (descending)
When disabled, the score subcommand passes data through unchanged.
Nextcloud output mode
The nextcloud output now defaults to append mode with a date separator. Each dispatch adds content below a ## YYYY-MM-DD HH:MM header, preserving previous entries.
Set "mode": "overwrite" in the output config to restore the old behavior:
The file output writes digests to the local filesystem. By default, only paths under ~/.openclaw/ are allowed. To authorize additional directories, use config.security.allowed_output_dirs:
All blocked attempts are logged to stderr with the reason.
Templates (agent usage)
Basic digest
# In agent tool call:
result = exec("python3 scripts/veille.py fetch --hours 24 --filter-seen --filter-topic")
data = json.loads(result.stdout)
# data["wrapped_listing"] is ready for LLM prompt injection# data["count"] = number of new articles# data["articles"] = list of article dicts
Prompt template
You are a news analyst. Here are today's articles:
{data["wrapped_listing"]}
Please summarize the 5 most important stories, focusing on security and tech.
Agent workflow example
1. Call veille fetch --filter-seen --filter-topic
2. Pipe through veille score (LLM scoring, if enabled)
3. If count > 0: pass wrapped_listing to LLM for analysis
4. LLM produces digest summary
5. Pipe through veille send (dispatches to configured outputs)
data = json.loads(fetch_output)
security_articles = [
a for a in data["articles"]
ifany(kw in a["title"].lower() for kw in ["cve", "vuln", "patch", "breach"])
]