🧪 Skills

Buzz

Real-time news aggregator with Discord & Telegram push. Manage Jin10, BlockBeats, RSS, X KOLs, Polymarket, OpenNews via REST API.

v1.1.1
❤️ 0
⬇️ 155
👁 1
Share

Description


name: buzz description: Real-time news aggregator with Discord & Telegram push. Manage Jin10, BlockBeats, RSS, X KOLs, Polymarket, OpenNews via REST API. version: 1.1.1 user-invocable: true metadata: openclaw: requires: bins: - node - npm - git emoji: "\U0001F4F0" os: - darwin - linux - win32

Buzz Skill

Install, run, and manage a real-time news aggregator with Discord & Telegram push notifications. All configuration is done via REST API with hot-reload — no restarts needed.

Base URL: http://localhost:3848 (default, configurable via dashboard.port)

Security Notice

  • config.json stores API keys, bot tokens, and webhook URLs locally. Never commit it to version control (it is gitignored by default).
  • If dashboard.password is empty, the REST API is unauthenticated. Always set a password when the dashboard is exposed beyond localhost.
  • The server binds to 0.0.0.0 by default. Use a reverse proxy or firewall to restrict access in production.
  • Review the source code at github.com/zxcnny930/buzz before running.

Quick Setup

git clone https://github.com/zxcnny930/buzz.git
cd buzz
npm install
cp config.example.json config.json  # Edit config.json and set dashboard.password before starting
npm start

The dashboard is at http://localhost:3848, settings page at /settings.html?lang=en.

Authentication

If a dashboard password is set, all /api/* endpoints require ?pw=PASSWORD:

curl -s "http://localhost:3848/api/config?pw=YOUR_PASSWORD"

If password is empty string, no authentication is needed.

IMPORTANT: All curl examples below omit ?pw= for brevity. If the server has a password configured, append ?pw=PASSWORD to every URL.

Auth failure response (HTTP 401):

{ "ok": false, "error": "Unauthorized" }

API Endpoints

1. Get Current Config

curl -s http://localhost:3848/api/config

Returns the full configuration JSON. Sensitive fields (apiKey, token, botToken, password) are redacted as "••••••" in the response.

2. Update Config (Partial, Hot-Reload)

POST /api/config accepts partial updates. Only send the sections you want to change.

Enable Jin10 with 10-second polling:

curl -s -X POST http://localhost:3848/api/config \
  -H "Content-Type: application/json" \
  -d '{"jin10": {"enabled": true, "pollIntervalMs": 10000}}'

Disable Polymarket:

curl -s -X POST http://localhost:3848/api/config \
  -H "Content-Type: application/json" \
  -d '{"polymarket": {"enabled": false}}'

Set Discord webhook:

curl -s -X POST http://localhost:3848/api/config \
  -H "Content-Type: application/json" \
  -d '{"discord": {"webhookUrl": "https://discord.com/api/webhooks/..."}}'

Enable Telegram:

curl -s -X POST http://localhost:3848/api/config \
  -H "Content-Type: application/json" \
  -d '{"telegram": {"enabled": true, "botToken": "123456:ABC-DEF", "chatId": "-1001234567890"}}'

Add an RSS source:

curl -s -X POST http://localhost:3848/api/config \
  -H "Content-Type: application/json" \
  -d '{"rssFeeds": [{"enabled": true, "name": "CoinDesk", "feedUrl": "https://www.coindesk.com/arc/outboundfeeds/rss/?outputType=xml", "pollIntervalMs": 300000, "color": 3447003}]}'

Note: rssFeeds is an array — sending it replaces the entire array, not appends.

Configure OpenNews AI filtering:

curl -s -X POST http://localhost:3848/api/config \
  -H "Content-Type: application/json" \
  -d '{"opennews": {"enabled": true, "pollIntervalMs": 60000, "minScore": 70, "signals": ["long"], "coins": ["BTC", "ETH"], "engineTypes": ["news", "listing"]}}'

Configure Polymarket alerts:

curl -s -X POST http://localhost:3848/api/config \
  -H "Content-Type: application/json" \
  -d '{"polymarket": {"enabled": true, "minChangePp": 5, "zThreshold": 2.5, "volSpikeThreshold": 2.0, "minLiquidity": 10000, "tagIds": [21, 120], "excludeTagIds": [100639]}}'

Set translation engine and AI model:

# Use Google Translate (free, default)
curl -s -X POST http://localhost:3848/api/config \
  -H "Content-Type: application/json" \
  -d '{"translator": "google"}'

# Use AI translation (OpenAI-compatible API)
curl -s -X POST http://localhost:3848/api/config \
  -H "Content-Type: application/json" \
  -d '{"translator": "ai", "ai": {"apiKey": "xai-...", "model": "grok-4.1-fast", "baseUrl": "https://api.x.ai/v1"}}'

Success response:

{ "ok": true }

Validation error response:

{
  "ok": false,
  "errors": ["polymarket.zThreshold must be > 0", "dashboard.port must be 1024-65535"]
}

3. Get Source Status

curl -s http://localhost:3848/api/status

Response:

{
  "jin10": { "active": true, "interval": 15000 },
  "blockbeats": { "active": true, "interval": 30000 },
  "polymarket": { "active": true, "interval": 180000 },
  "x6551": { "active": true, "interval": 3600000 },
  "opennews": { "active": false, "interval": 60000 },
  "rss:https://www.blocktempo.com/feed/": { "active": true, "interval": 300000 }
}

Each key is a source identifier. RSS sources are prefixed with rss: followed by their feed URL.

4. Manage KOL Tracking List

List all tracked accounts:

curl -s -X POST http://localhost:3848/api/kols \
  -H "Content-Type: application/json" \
  -d '{"action": "list"}'

Response:

{ "ok": true, "kols": ["elonmusk", "VitalikButerin"] }

Add a KOL:

curl -s -X POST http://localhost:3848/api/kols \
  -H "Content-Type: application/json" \
  -d '{"action": "add", "username": "caboronli"}'

Response:

{ "ok": true, "kols": ["elonmusk", "VitalikButerin", "caboronli"] }

If already exists:

{ "ok": true, "message": "already exists", "kols": ["elonmusk", "VitalikButerin", "caboronli"] }

Remove a KOL:

curl -s -X POST http://localhost:3848/api/kols \
  -H "Content-Type: application/json" \
  -d '{"action": "remove", "username": "elonmusk"}'

Response:

{ "ok": true, "kols": ["VitalikButerin", "caboronli"] }

If username not found:

{ "ok": false, "error": "not found", "kols": ["VitalikButerin", "caboronli"] }

Username strings are trimmed and @ prefix is automatically stripped.

5. Health Check

curl -s http://localhost:3848/health

Response:

{ "ok": true, "clients": 2, "history": 150 }
  • clients: number of active SSE connections
  • history: number of events in memory

No authentication required.

6. Server-Sent Events (Live Stream)

curl -s -N http://localhost:3848/sse

Streams real-time news events as SSE. On connection, all historical events are sent first, then new events arrive in real-time. Heartbeat every 15 seconds.


Full Configuration Schema

jin10

Field Type Default Validation Description
enabled boolean true Enable Jin10 flash news
pollIntervalMs number 15000 >= 5000 Poll interval in milliseconds
onlyImportant boolean true Only push important items

blockbeats

Field Type Default Validation Description
enabled boolean true Enable BlockBeats
pollIntervalMs number 30000 >= 5000 Poll interval
onlyImportant boolean true Only push important items
lang string "cht" Language: cht (Trad. Chinese), en, cn (Simp. Chinese)

rssFeeds (array)

Field Type Default Validation Description
enabled boolean true Enable this feed
name string Display name
feedUrl string must start with http(s):// RSS/Atom feed URL
pollIntervalMs number 300000 >= 5000 Poll interval
color number Discord embed color as integer (e.g. 3447003 = #3498DB)

x6551

Field Type Default Validation Description
enabled boolean true Enable X tweet monitoring
apiBase string "https://ai.6551.io" must start with http(s):// API base URL
token string API token from 6551.io/mcp
pollIntervalMs number 3600000 >= 5000 Poll interval
kolSyncIntervalMs number 300000 KOL list refresh interval
kols string[] [] Usernames to monitor (without @)

opennews

Field Type Default Validation Description
enabled boolean false Enable OpenNews AI news
pollIntervalMs number 60000 >= 5000 Poll interval
minScore number 70 0-100 Minimum AI score to push
signals string[] [] Filter: "long", "short", "neutral" (empty = all)
coins string[] [] Filter by coin symbols, e.g. ["BTC","ETH"] (empty = all). OpenNews-only — other sources (Jin10, BlockBeats, RSS, Polymarket) cannot be coin-filtered.
engineTypes string[] [] Filter: "news", "listing", "onchain", "meme", "market" (empty = all). OpenNews-only.

polymarket

Field Type Default Validation Description
enabled boolean true Enable Polymarket monitoring
priceSpikeEnabled boolean true Enable price spike alerts
volumeSpikeEnabled boolean true Enable volume spike alerts
pollIntervalMs number 180000 >= 5000 Price check interval
marketRefreshMs number 600000 >= 60000 Market list refresh interval
minChangePp number 5 Min percentage point change to alert
zThreshold number 2.5 > 0 Z-Score anomaly threshold (0 = off)
volSpikeThreshold number 2.0 > 0 Volume spike multiplier
minLiquidity number 10000 >= 0 Min market liquidity in USD
rollingWindowMinutes number 30 Window for price change calculation
cooldownMs number 900000 >= 60000 Min interval before re-alerting same market
tagIds number[] [] Only track these categories (empty = all)
excludeTagIds number[] [] Exclude these categories

Polymarket Tag IDs:

ID Category
21 Crypto
2 Politics
120 Finance
1401 Tech
596 Culture
100265 Geopolitics
100639 Sports

translator (top-level)

Value Description Requires
"google" Google Translate (free, no key needed) default
"ai" Use ai section API (Grok/GPT/Claude/DeepSeek…) ai.apiKey
"none" No translation, show English as-is

ai (AI Translation)

Field Type Default Validation Description
apiKey string API key for translation
model string "grok-4.1-fast" Model name (any OpenAI-compatible)
baseUrl string "https://api.x.ai/v1" must start with http(s):// API endpoint

Supported models: grok-4.1-fast, gpt-4o-mini, gpt-4.1-mini, claude-sonnet-4-6, claude-haiku-4-5-20251001, gemini-2.0-flash, or any OpenAI-compatible model.

discord

Field Type Default Description
webhookUrl string "" Discord webhook URL (simple mode)
botToken string "" Discord bot token (advanced mode)
channelId string "" Discord channel ID (required for bot mode)

Use either webhookUrl or botToken + channelId, not both.

telegram

Field Type Default Description
enabled boolean false Enable Telegram notifications
botToken string "" Telegram bot token from @BotFather
chatId string "" Target chat/group/channel ID

dashboard

Field Type Default Validation Description
port number 3848 1024-65535 HTTP server port (restart required)
password string "" Access password (empty = no auth)

Common Workflows

Check what's currently running

curl -s http://localhost:3848/api/status | jq 'to_entries[] | select(.value.active) | .key'

Enable a source and verify

# Enable Jin10
curl -s -X POST http://localhost:3848/api/config \
  -H "Content-Type: application/json" \
  -d '{"jin10": {"enabled": true, "pollIntervalMs": 15000}}'

# Verify it's active
curl -s http://localhost:3848/api/status | jq '.jin10'

Set up Discord + Telegram dual push

curl -s -X POST http://localhost:3848/api/config \
  -H "Content-Type: application/json" \
  -d '{
    "discord": {"webhookUrl": "https://discord.com/api/webhooks/..."},
    "telegram": {"enabled": true, "botToken": "123456:ABC-DEF", "chatId": "-1001234567890"}
  }'

Add a new RSS feed (without losing existing ones)

IMPORTANT: rssFeeds is an array. POSTing it replaces the entire list. You must GET first, append, then POST back.

Step 1 — Get current feeds:

curl -s http://localhost:3848/api/config | jq '.rssFeeds'

Step 2 — POST the full array with the new feed appended:

# Example: existing feeds are BlockTempo and PTS News, adding CoinDesk
curl -s -X POST http://localhost:3848/api/config \
  -H "Content-Type: application/json" \
  -d '{"rssFeeds": [
    {"enabled": true, "name": "BlockTempo", "feedUrl": "https://www.blocktempo.com/feed/", "pollIntervalMs": 300000, "color": 16746496},
    {"enabled": true, "name": "PTS News", "feedUrl": "https://news.pts.org.tw/xml/newsfeed.xml", "pollIntervalMs": 300000, "color": 3447003},
    {"enabled": true, "name": "CoinDesk", "feedUrl": "https://www.coindesk.com/arc/outboundfeeds/rss/?outputType=xml", "pollIntervalMs": 300000, "color": 2067276}
  ]}'

Same pattern applies when removing or editing an RSS feed — always send the complete updated array.

Remove an RSS feed

GET current list, remove the target, POST back the remaining array.

# Get current feeds, then POST without the one you want to remove
curl -s http://localhost:3848/api/config | jq '.rssFeeds'
# POST back the array minus the removed feed
curl -s -X POST http://localhost:3848/api/config \
  -H "Content-Type: application/json" \
  -d '{"rssFeeds": [
    {"enabled": true, "name": "BlockTempo", "feedUrl": "https://www.blocktempo.com/feed/", "pollIntervalMs": 300000, "color": 16746496}
  ]}'

Add an item to any array field (general pattern)

When the user says "also add X", always follow GET → modify → POST:

# Step 1: GET current value
CURRENT=$(curl -s http://localhost:3848/api/config | jq '.polymarket.tagIds')
# Example result: [21, 120]

# Step 2: Append and POST back
# Adding Sports (100639) to existing [21, 120]
curl -s -X POST http://localhost:3848/api/config \
  -H "Content-Type: application/json" \
  -d '{"polymarket": {"tagIds": [21, 120, 100639]}}'

Same pattern applies to opennews.signals, opennews.coins, opennews.engineTypes, polymarket.excludeTagIds.

Monitor high-impact crypto news only

curl -s -X POST http://localhost:3848/api/config \
  -H "Content-Type: application/json" \
  -d '{"opennews": {"enabled": true, "minScore": 80, "signals": ["long", "short"], "coins": ["BTC", "ETH", "SOL"], "engineTypes": ["news", "listing"]}}'

Track new KOL and verify

# Add
curl -s -X POST http://localhost:3848/api/kols \
  -H "Content-Type: application/json" \
  -d '{"action": "add", "username": "VitalikButerin"}'

# List all
curl -s -X POST http://localhost:3848/api/kols \
  -H "Content-Type: application/json" \
  -d '{"action": "list"}'

Important Rules

Array fields are REPLACED, never merged

The config deep-merge only merges plain objects. All array fields are completely replaced when you POST them. If the user wants to add an item to an existing list, you MUST GET the current config first, modify the array, then POST back.

Array fields that require GET-first when adding/removing items:

Field Example "add" intent
rssFeeds "Add CoinDesk RSS" — GET current feeds, append, POST full array
polymarket.tagIds "Also track Sports" — GET current tagIds, append 100639, POST
polymarket.excludeTagIds "Also exclude Culture" — same pattern
opennews.signals "Also show long signals" — GET, append "long", POST
opennews.coins "Also track SOL" — GET, append "SOL", POST
opennews.engineTypes "Also include listings" — GET, append "listing", POST

Exception — KOLs have a safe endpoint: Use POST /api/kols with action: "add" or "remove". This does NOT require GET-first. Do NOT modify x6551.kols via POST /api/config — use the dedicated endpoint instead.

When the user says "set to" (replace entire list) instead of "add", you can POST directly without GET-first. Example: "I only want Crypto and Finance" → {"polymarket": {"tagIds": [21, 120]}} is fine.

Other rules

  1. Object sections support partial update. You can POST just {"jin10": {"enabled": false}} without affecting other jin10 fields or other sections.
  2. Sensitive fields are redacted in GET responses as "••••••". When POSTing, redacted values are automatically preserved (not overwritten).
  3. All changes are hot-reloaded — no restart needed, except dashboard.port.
  4. The x6551.token is shared between X tweet monitor and OpenNews.
  5. Get your 6551 API token at https://6551.io/mcp

Error Responses

HTTP Status Body Cause
401 { "ok": false, "error": "Unauthorized" } Missing or wrong ?pw= password
400 { "ok": false, "errors": [...] } Validation failed (array of error strings)
400 { "ok": false, "error": "Invalid JSON" } Malformed request body
404 { "error": "Not found" } Unknown API route

Reviews (0)

Sign in to write a review.

No reviews yet. Be the first to review!

Comments (0)

Sign in to join the discussion.

No comments yet. Be the first to share your thoughts!

Compatible Platforms

Pricing

Free

Related Configs