| Time | Task | Details |
Editorial Process — Manneken Newsletter & Press Review 🌟
Daily Schedule (Brussels time, Mon–Fri)
| Time | Task | Details |
|---|---|---|
| 7:00 | Cache press sources | Runs scripts/fetch-press.sh via lightpanda: BX1 🇫🇷, BRUZZ 🇳🇱, RTBF 🇫🇷, Brussels Times 🇬🇧, IRCEL air quality |
| 7:10 | Write trilingual press review | AI writes EN/FR/NL versions from cached sources → docs/press-reviews/ + site/src/content/blog/ |
| 7:25 | Post to channels | Twitter (thread), Nostr (3 notes), Discord #📰press-review |
| 7:30 | Send daily newsletter | Email to weekday subscribers in their language (EN/FR/NL/AR/ZH) |
| 7:35 | Generate podcast | EN audio (Xavier + Leen voices) + FR audio (Raymond Devos + Annie Cordy voices) via ElevenLabs |
Weekend Schedule
| Day | Time | Task |
|---|---|---|
| Saturday | 7:00–7:25 | Same as weekday (press review + post) |
| Saturday | 7:30 | Weekly newsletter with week summary + "What to do in Brussels this weekend?" |
| Saturday | 7:35 | Podcast generation |
| Sunday | 7:00–7:35 | Press review + podcast (no newsletter) |
Press Sources
| Source | Language | Method | URL |
|---|---|---|---|
| BX1 | French | Lightpanda markdown | https://bx1.be/news/ |
| BRUZZ | Dutch | Lightpanda markdown | https://www.bruzz.be/actua |
| RTBF | French | Lightpanda markdown | https://www.rtbf.be/en-continu |
| Brussels Times | English | Google News sitemap XML | https://www.brusselstimes.com/google-news-sitemap.xml |
| IRCEL-CELINE | Multi | Lightpanda markdown | https://www.irceline.be/en/air-quality/measurements/information-and-alarm-thresholds |
Newsletter
Editions
- Daily (Mon–Fri): That morning's press review with weather forecast and air quality
- Weekly (Saturday): Week's highlights + "What to do in Brussels this weekend?"
- Subscribers can choose daily, weekly, or both
Languages
English, Français, Nederlands, العربية, 中文
Arabic and Chinese currently receive English content with localized subject lines, labels, and UI.
Email Structure
- ☁️ Weather forecast (always first — current temp, min/max, feels-like, wind, humidity)
- 🟡 Air quality alert (only if AQI > 100)
- 📰 Press review content (grouped by topic, sources cited)
- 🎉 Weekend events (weekly edition only)
- 🔗 Footer with manage preferences + one-click unsubscribe
Infrastructure
- Subscribe: https://manneken.brussels/newsletter/
- Archive: https://manneken.brussels/newsletter/archive/
- Database: SQLite at
data/newsletter.db - API server: systemd
newsletter-apion port 3847 (behind nginx) - Email provider: Resend (from: newsletter@manneken.brussels)
Subscriber Management
/newsletter/subscribe— sign up (POST)/newsletter/unsubscribe?token=xxx— one-click removal (GET)/newsletter/manage?token=xxx— change language, switch edition (GET/POST)
Podcast
Voices (ElevenLabs)
| Language | Host 1 | Host 2 |
|---|---|---|
| English | Xavier (Manneken) | Leen (co-host) |
| French | Raymond Devos (Manneken) | Annie Cordy (co-host) |
Rules
- Hosts introduce themselves ONCE by voice name at the start
- No "Speaker:" prefixes in scripts — voices make it clear
- Weather forecast near the top
- If ElevenLabs fails: stop, don't create placeholder files
- Valid MP3 must be >100KB
Tools
- Scraping: Always lightpanda (
/usr/local/bin/lightpanda fetch --dump markdown --obey_robots <URL>) - TTS: ElevenLabs API (multilingual v2 model)
- Email: Resend API
- Site: Astro + Tailwind, deployed via
scripts/deploy-site.sh
Stats
Tracked in docs/private/chat-stats.json:
- Daily/monthly chat metrics (Nostr, Discord, Twitter)
- Newsletter subscriber counts (by language + edition)
- Emails sent per day (by language)
Press Review Writing Rules
"Saved You a Click" — Always Include Specifics
Every summary, teaser, tweet, and Discord post must contain enough detail that readers don't need to click through to understand the story. Name people, places, initiatives, and numbers.
Bad: "A square in Brussels was redone." Good: "The Tootschmarket square in Molenbeek reopened after 18 months of works."
Apply to: Discord summaries, Twitter thread text, Nostr teasers, LinkedIn posts, newsletter intro lines.
Costume of the Day Image
Every press review now starts with an illustrated Manneken Pis costume that matches the day’s news or calendar moment.
- Run the generator after the trilingual posts are saved (EN/FR/NL files in
docs/press-reviews/andsite/src/content/blog/).cd /root/.openclaw/workspace node scripts/generate-costume-image.mjs --date YYYY-MM-DD- Add
--forceto regenerate even if the PNG already exists.
- Add
- What the script does automatically:
- Scans the English review for keywords (Ramadan/iftar, XR, EU summit, mobility crackdowns, weather extremes, football, etc.) to pick a costume theme.
- If no obvious topic is found, checks hard-coded calendar moments (Saint-Patrick, 22 mars commemoration, Fête nationale, etc.).
- If nothing matches, falls back to the official dressing calendar (cached under
docs/cache/manneken-costumes/via lightpanda scraping of the monthly schedule). If that page is blocked, a basic seasonal theme is used so the image still appears. - Generates a 1024×1024 PNG via OpenAI (
skills/openai-image-gen) and stores it atsite/public/news/costumes/YYYY/MM/YYYY-MM-DD-costume.png. - Inserts a localized snippet (EN/FR/NL) immediately under the frontmatter of each press-review Markdown file:
<!-- COSTUME-IMAGE:2026-03-19 -->  <small>Costume du jour : …</small> <!-- /COSTUME-IMAGE -->
- Image sourcing:
- Source:
site/public/news/costumes/YYYY/MM/ - Cached schedule:
docs/cache/manneken-costumes/<year>-<month>.md - Temporary OpenAI output:
tmp/costume-image/
- Source:
- When to rerun: anytime the review content changes meaningfully (new topics or reordering). Use
--forceto update the PNG + snippets.
ℹ️ Note: the official garde-robe site sits behind Cloudflare, so the monthly schedule is temporarily sourced from https://bruxelles-city-news.be/ until we can ingest the PDF directly via
opendataloader-pdf.