From lazy-obsidian
Veille quotidienne articles cyber — récupère les articles RSS Krebs/BleepingComputer/ANSSI/CERT-FR des dernières 24h, scoring mots-clés, écrit max 3 fichiers dans _Inbox/raw/articles/ avec résumé 3 lignes (defuddle). Idempotent via seen_urls. Encoding UTF-8 systématique.
How this skill is triggered — by the user, by Claude, or both
Slash command
/lazy-obsidian:articles-veilleThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Avaler les articles RSS cyber des dernières 24h, scorer par mots-clés, garder les 3 plus pertinents, écrire un fichier par article dans `_Inbox/raw/articles/` avec résumé 3 lignes. Idempotent via dédup sha256(URL).
Avaler les articles RSS cyber des dernières 24h, scorer par mots-clés, garder les 3 plus pertinents, écrire un fichier par article dans _Inbox/raw/articles/ avec résumé 3 lignes. Idempotent via dédup sha256(URL).
Idem cve-veille — encoding UTF-8 sans BOM impératif pour tous les writes (Set-Content -Encoding utf8 -NoNewline, Add-Content -Encoding utf8). Lecture en Get-Content -Raw -Encoding utf8.
$statePath = "D:\tommyDossier\Documents\Obsidian Vault\99-Meta\lazy-obsidian-state.json"
$state = Get-Content $statePath -Raw -Encoding utf8 | ConvertFrom-Json
$lastRun = $state.last_run.'articles-veille'
$seenUrls = $state.seen_urls
Si $lastRun correspond à aujourd'hui → SKIP_IDEMPOTENT (idem cve-veille).
| Source | URL |
|---|---|
| Krebs on Security | https://krebsonsecurity.com/feed/ |
| BleepingComputer | https://www.bleepingcomputer.com/feed/ |
| ANSSI / CERT-FR alerts | https://www.cert.ssi.gouv.fr/feed/ |
| CERT-FR avis | https://www.cert.ssi.gouv.fr/avis/feed/ |
Pour chaque source, try/catch indépendant :
try {
$rss = Invoke-RestMethod -Uri $url -TimeoutSec 30
# Parser <item> dont pubDate ∈ fenêtre
} catch {
$sourcesFailed += $sourceName
continue
}
Pour chaque article candidat :
$urlHash = (Get-FileHash -Algorithm SHA256 -InputStream ([System.IO.MemoryStream]::new([System.Text.Encoding]::UTF8.GetBytes($url)))).Hash.ToLower()
if ($seenUrls -contains "sha256:$urlHash") { continue }
Calculer un score par article (case-insensitive, dans title + description) :
| Mot-clé | Poids |
|---|---|
zero-day / 0-day | 5 |
RCE / remote code execution | 4 |
ransomware | 3 |
APT / nation-state | 3 |
CVE- (regex CVE-\d{4}-\d+) | 3 |
breach / leak | 2 |
exploit | 2 |
vulnerability / vulnérabilité | 1 |
patch / update | 1 |
$candidates | Sort-Object @{e='score';desc=$true}, @{e='pubDate';desc=$true} | Select-Object -First 3
Plafond strict : 3 articles par run.
a. Tenter defuddle sur l'URL pour récupérer un markdown propre :
Le skill defuddle (Kepano) est dans .claude/skills/defuddle/. Invocation : utilise defuddle pour extraire le contenu propre. Si succès → markdown propre, sinon → exception ou contenu vide.
b. Si defuddle réussit : générer un résumé 3 lignes via LLM (toi, Claude). Prompt suggéré :
"Résume cet article cyber en exactement 3 lignes, en français, factuel. Ne pas inclure d'opinion."
c. Si defuddle échoue (Cloudflare, JS-only, paywall, exception) : defuddle_failed: true, pas de résumé, fichier minimal.
d. Calculer le slug :
$slug = $title.ToLower() -replace '[^a-z0-9]+','-' -replace '^-|-$','' | ForEach-Object { if ($_.Length -gt 60) { $_.Substring(0,60) } else { $_ } }
e. Écrire le fichier _Inbox\raw\articles\<YYYY-MM-DD>-<slug>.md :
---
titre: "<titre original>"
type: concept
cluster: <cluster_inferé_ou_99-Meta>
statut: draft
importance: deep-cut
source_knowledge: community-validated
source: <Krebs|BleepingComputer|ANSSI|CERT-FR>
url: <URL>
date_publication: <YYYY-MM-DD>
defuddle_failed: <true|false>
tags: ["#meta/veille-auto", "#cyber/article"]
date_maj: <YYYY-MM-DD>
---
# <titre>
> [!info] Source
> <Source> · [Lien](<URL>) · publié <date_publication>
## Résumé (3 lignes)
<Résumé LLM 3 lignes — ou message "defuddle a échoué, lire la source originale" si defuddle_failed>
## À investiguer
- [ ] Pertinence pour le vault (vs `_Archives/_Inbox-purged/`)
- [ ] Cluster cible si promotion
- [ ] Wikilinks vers pages existantes
Set-Content -Path $articlePath -Value $content -Encoding utf8 -NoNewline
f. Slug collision : si <YYYY-MM-DD>-<slug>.md existe déjà → suffixer -2, -3, etc.
| Mots-clés | Cluster |
|---|---|
red team, pentest, offensive, BloodHound | 01-Red-Team |
SOC, SIEM, EDR, detection | 02-Blue-Team |
crypto, TLS, certificate | 03-Cryptographie ou 04-Reseau-Protocoles |
web, XSS, SQLi, OWASP | 05-AppSec-DevSecOps |
cloud, AWS, Azure, K8s | 06-Cloud-Security |
AD, Kerberos, Entra | 07-IAM-ActiveDirectory |
forensics, DFIR, IR | 08-Forensics-DFIR |
malware, ransomware, RAT | 09-Malware-Analysis |
reverse, ghidra, IDA | 10-Reverse-Engineering |
ICS, SCADA, OT | 11-IoT-OT-ICS |
Android, iOS, mobile | 12-Mobile-Security |
RGPD, NIS2, compliance | 13-Governance-Compliance |
MITRE, STIX, IOC, APT | 14-Threat-Intelligence |
Zero Trust, BeyondCorp | 15-Zero-Trust-Architecture |
| (ambigu) | 99-Meta |
$state.last_run.'articles-veille' = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
foreach ($url in $retainedUrls) {
$hash = "sha256:$((Get-FileHash ... ).Hash.ToLower())"
$state.seen_urls += $hash
}
$state | ConvertTo-Json -Depth 5 | Set-Content -Path $statePath -Encoding utf8 -NoNewline
$runEntry = @{
ts = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
skill = "articles-veille"
status = "OK" # ou PARTIAL, FAIL, SKIP_IDEMPOTENT
new = $retainedCount
skipped = $skippedCount
errors = $errorCount
sources_failed = $sourcesFailed
} | ConvertTo-Json -Compress
Add-Content -Path "...\99-Meta\lazy-obsidian-runs.jsonl" -Value $runEntry -Encoding utf8
✅ articles-veille — 2 articles retenus, 1 source en échec (ANSSI), 12 articles filtrés.
- "BlackCat ransomware update" (Krebs, score 11) → _Inbox/raw/articles/
- "Zero-day in Exchange" (BleepingComputer, score 8) → _Inbox/raw/articles/
Idem cve-veille + spécifique :
| Erreur | Action |
|---|---|
defuddle fail | defuddle_failed: true, fichier minimal — pas une erreur fatale |
| RSS malformé | Skip cette source, log sources_failed, continue |
| Slug collision | Suffixer -2, -3, etc. |
| Set-Content échoue (verrou Obsidian) | Retry 2s, sinon skip cet article |
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub tommyrequillard/lazy-obsidian --plugin lazy-obsidian