/install buzz
\r \r
Buzz Skill\r
\r
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.\r
\r
Base URL: http://localhost:3848 (default, configurable via dashboard.port)\r
\r
Security Notice\r
\r
config.jsonstores API keys, bot tokens, and webhook URLs locally. Never commit it to version control (it is gitignored by default).\r- If
dashboard.passwordis empty, the REST API is unauthenticated. Always set a password when the dashboard is exposed beyond localhost.\r - The server binds to
0.0.0.0by default. Use a reverse proxy or firewall to restrict access in production.\r - Review the source code at github.com/zxcnny930/buzz before running.\r \r
Quick Setup\r
\r
git clone https://github.com/zxcnny930/buzz.git\r
cd buzz\r
npm install\r
cp config.example.json config.json # Edit config.json and set dashboard.password before starting\r
npm start\r
```\r
\r
The dashboard is at `http://localhost:3848`, settings page at `/settings.html?lang=en`.\r
\r
## Authentication\r
\r
If a dashboard password is set, all `/api/*` endpoints require `?pw=PASSWORD`:\r
\r
```bash\r
curl -s "http://localhost:3848/api/config?pw=YOUR_PASSWORD"\r
```\r
\r
If password is empty string, no authentication is needed.\r
\r
**IMPORTANT: All curl examples below omit `?pw=` for brevity. If the server has a password configured, append `?pw=PASSWORD` to every URL.**\r
\r
Auth failure response (HTTP 401):\r
\r
```json\r
{ "ok": false, "error": "Unauthorized" }\r
```\r
\r
---\r
\r
## API Endpoints\r
\r
### 1. Get Current Config\r
\r
```bash\r
curl -s http://localhost:3848/api/config\r
```\r
\r
Returns the full configuration JSON. Sensitive fields (apiKey, token, botToken, password) are redacted as `"••••••"` in the response.\r
\r
### 2. Update Config (Partial, Hot-Reload)\r
\r
`POST /api/config` accepts partial updates. Only send the sections you want to change.\r
\r
**Enable Jin10 with 10-second polling:**\r
\r
```bash\r
curl -s -X POST http://localhost:3848/api/config \\r
-H "Content-Type: application/json" \\r
-d '{"jin10": {"enabled": true, "pollIntervalMs": 10000}}'\r
```\r
\r
**Disable Polymarket:**\r
\r
```bash\r
curl -s -X POST http://localhost:3848/api/config \\r
-H "Content-Type: application/json" \\r
-d '{"polymarket": {"enabled": false}}'\r
```\r
\r
**Set Discord webhook:**\r
\r
```bash\r
curl -s -X POST http://localhost:3848/api/config \\r
-H "Content-Type: application/json" \\r
-d '{"discord": {"webhookUrl": "https://discord.com/api/webhooks/..."}}'\r
```\r
\r
**Enable Telegram:**\r
\r
```bash\r
curl -s -X POST http://localhost:3848/api/config \\r
-H "Content-Type: application/json" \\r
-d '{"telegram": {"enabled": true, "botToken": "123456:ABC-DEF", "chatId": "-1001234567890"}}'\r
```\r
\r
**Add an RSS source:**\r
\r
```bash\r
curl -s -X POST http://localhost:3848/api/config \\r
-H "Content-Type: application/json" \\r
-d '{"rssFeeds": [{"enabled": true, "name": "CoinDesk", "feedUrl": "https://www.coindesk.com/arc/outboundfeeds/rss/?outputType=xml", "pollIntervalMs": 300000, "color": 3447003}]}'\r
```\r
\r
> Note: `rssFeeds` is an array — sending it replaces the entire array, not appends.\r
\r
**Configure OpenNews AI filtering:**\r
\r
```bash\r
curl -s -X POST http://localhost:3848/api/config \\r
-H "Content-Type: application/json" \\r
-d '{"opennews": {"enabled": true, "pollIntervalMs": 60000, "minScore": 70, "signals": ["long"], "coins": ["BTC", "ETH"], "engineTypes": ["news", "listing"]}}'\r
```\r
\r
**Configure Polymarket alerts:**\r
\r
```bash\r
curl -s -X POST http://localhost:3848/api/config \\r
-H "Content-Type: application/json" \\r
-d '{"polymarket": {"enabled": true, "minChangePp": 5, "zThreshold": 2.5, "volSpikeThreshold": 2.0, "minLiquidity": 10000, "tagIds": [21, 120], "excludeTagIds": [100639]}}'\r
```\r
\r
**Set translation engine and AI model:**\r
\r
```bash\r
# Use Google Translate (free, default)\r
curl -s -X POST http://localhost:3848/api/config \\r
-H "Content-Type: application/json" \\r
-d '{"translator": "google"}'\r
\r
# Use AI translation (OpenAI-compatible API)\r
curl -s -X POST http://localhost:3848/api/config \\r
-H "Content-Type: application/json" \\r
-d '{"translator": "ai", "ai": {"apiKey": "xai-...", "model": "grok-4.1-fast", "baseUrl": "https://api.x.ai/v1"}}'\r
```\r
\r
**Success response:**\r
\r
```json\r
{ "ok": true }\r
```\r
\r
**Validation error response:**\r
\r
```json\r
{\r
"ok": false,\r
"errors": ["polymarket.zThreshold must be > 0", "dashboard.port must be 1024-65535"]\r
}\r
```\r
\r
### 3. Get Source Status\r
\r
```bash\r
curl -s http://localhost:3848/api/status\r
```\r
\r
**Response:**\r
\r
```json\r
{\r
"jin10": { "active": true, "interval": 15000 },\r
"blockbeats": { "active": true, "interval": 30000 },\r
"polymarket": { "active": true, "interval": 180000 },\r
"x6551": { "active": true, "interval": 3600000 },\r
"opennews": { "active": false, "interval": 60000 },\r
"rss:https://www.blocktempo.com/feed/": { "active": true, "interval": 300000 }\r
}\r
```\r
\r
Each key is a source identifier. RSS sources are prefixed with `rss:` followed by their feed URL.\r
\r
### 4. Manage KOL Tracking List\r
\r
**List all tracked accounts:**\r
\r
```bash\r
curl -s -X POST http://localhost:3848/api/kols \\r
-H "Content-Type: application/json" \\r
-d '{"action": "list"}'\r
```\r
\r
Response:\r
\r
```json\r
{ "ok": true, "kols": ["elonmusk", "VitalikButerin"] }\r
```\r
\r
**Add a KOL:**\r
\r
```bash\r
curl -s -X POST http://localhost:3848/api/kols \\r
-H "Content-Type: application/json" \\r
-d '{"action": "add", "username": "caboronli"}'\r
```\r
\r
Response:\r
\r
```json\r
{ "ok": true, "kols": ["elonmusk", "VitalikButerin", "caboronli"] }\r
```\r
\r
If already exists:\r
\r
```json\r
{ "ok": true, "message": "already exists", "kols": ["elonmusk", "VitalikButerin", "caboronli"] }\r
```\r
\r
**Remove a KOL:**\r
\r
```bash\r
curl -s -X POST http://localhost:3848/api/kols \\r
-H "Content-Type: application/json" \\r
-d '{"action": "remove", "username": "elonmusk"}'\r
```\r
\r
Response:\r
\r
```json\r
{ "ok": true, "kols": ["VitalikButerin", "caboronli"] }\r
```\r
\r
If username not found:\r
\r
```json\r
{ "ok": false, "error": "not found", "kols": ["VitalikButerin", "caboronli"] }\r
```\r
\r
> Username strings are trimmed and `@` prefix is automatically stripped.\r
\r
### 5. Health Check\r
\r
```bash\r
curl -s http://localhost:3848/health\r
```\r
\r
Response:\r
\r
```json\r
{ "ok": true, "clients": 2, "history": 150 }\r
```\r
\r
- `clients`: number of active SSE connections\r
- `history`: number of events in memory\r
\r
No authentication required.\r
\r
### 6. Server-Sent Events (Live Stream)\r
\r
```bash\r
curl -s -N http://localhost:3848/sse\r
```\r
\r
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.\r
\r
---\r
\r
## Full Configuration Schema\r
\r
### jin10\r
\r
| Field | Type | Default | Validation | Description |\r
|-------|------|---------|------------|-------------|\r
| `enabled` | boolean | `true` | | Enable Jin10 flash news |\r
| `pollIntervalMs` | number | `15000` | >= 5000 | Poll interval in milliseconds |\r
| `onlyImportant` | boolean | `true` | | Only push important items |\r
\r
### blockbeats\r
\r
| Field | Type | Default | Validation | Description |\r
|-------|------|---------|------------|-------------|\r
| `enabled` | boolean | `true` | | Enable BlockBeats |\r
| `pollIntervalMs` | number | `30000` | >= 5000 | Poll interval |\r
| `onlyImportant` | boolean | `true` | | Only push important items |\r
| `lang` | string | `"cht"` | | Language: `cht` (Trad. Chinese), `en`, `cn` (Simp. Chinese) |\r
\r
### rssFeeds (array)\r
\r
| Field | Type | Default | Validation | Description |\r
|-------|------|---------|------------|-------------|\r
| `enabled` | boolean | `true` | | Enable this feed |\r
| `name` | string | | | Display name |\r
| `feedUrl` | string | | must start with `http(s)://` | RSS/Atom feed URL |\r
| `pollIntervalMs` | number | `300000` | >= 5000 | Poll interval |\r
| `color` | number | | | Discord embed color as integer (e.g. `3447003` = `#3498DB`) |\r
\r
### x6551\r
\r
| Field | Type | Default | Validation | Description |\r
|-------|------|---------|------------|-------------|\r
| `enabled` | boolean | `true` | | Enable X tweet monitoring |\r
| `apiBase` | string | `"https://ai.6551.io"` | must start with `http(s)://` | API base URL |\r
| `token` | string | | | API token from [6551.io/mcp](https://6551.io/mcp) |\r
| `pollIntervalMs` | number | `3600000` | >= 5000 | Poll interval |\r
| `kolSyncIntervalMs` | number | `300000` | | KOL list refresh interval |\r
| `kols` | string[] | `[]` | | Usernames to monitor (without @) |\r
\r
### opennews\r
\r
| Field | Type | Default | Validation | Description |\r
|-------|------|---------|------------|-------------|\r
| `enabled` | boolean | `false` | | Enable OpenNews AI news |\r
| `pollIntervalMs` | number | `60000` | >= 5000 | Poll interval |\r
| `minScore` | number | `70` | 0-100 | Minimum AI score to push |\r
| `signals` | string[] | `[]` | | Filter: `"long"`, `"short"`, `"neutral"` (empty = all) |\r
| `coins` | string[] | `[]` | | Filter by coin symbols, e.g. `["BTC","ETH"]` (empty = all). **OpenNews-only** — other sources (Jin10, BlockBeats, RSS, Polymarket) cannot be coin-filtered. |\r
| `engineTypes` | string[] | `[]` | | Filter: `"news"`, `"listing"`, `"onchain"`, `"meme"`, `"market"` (empty = all). **OpenNews-only.** |\r
\r
### polymarket\r
\r
| Field | Type | Default | Validation | Description |\r
|-------|------|---------|------------|-------------|\r
| `enabled` | boolean | `true` | | Enable Polymarket monitoring |\r
| `priceSpikeEnabled` | boolean | `true` | | Enable price spike alerts |\r
| `volumeSpikeEnabled` | boolean | `true` | | Enable volume spike alerts |\r
| `pollIntervalMs` | number | `180000` | >= 5000 | Price check interval |\r
| `marketRefreshMs` | number | `600000` | >= 60000 | Market list refresh interval |\r
| `minChangePp` | number | `5` | | Min percentage point change to alert |\r
| `zThreshold` | number | `2.5` | > 0 | Z-Score anomaly threshold (0 = off) |\r
| `volSpikeThreshold` | number | `2.0` | > 0 | Volume spike multiplier |\r
| `minLiquidity` | number | `10000` | >= 0 | Min market liquidity in USD |\r
| `rollingWindowMinutes` | number | `30` | | Window for price change calculation |\r
| `cooldownMs` | number | `900000` | >= 60000 | Min interval before re-alerting same market |\r
| `tagIds` | number[] | `[]` | | Only track these categories (empty = all) |\r
| `excludeTagIds` | number[] | `[]` | | Exclude these categories |\r
\r
**Polymarket Tag IDs:**\r
\r
| ID | Category |\r
|----|----------|\r
| 21 | Crypto |\r
| 2 | Politics |\r
| 120 | Finance |\r
| 1401 | Tech |\r
| 596 | Culture |\r
| 100265 | Geopolitics |\r
| 100639 | Sports |\r
\r
### translator (top-level)\r
\r
| Value | Description | Requires |\r
|-------|-------------|----------|\r
| `"google"` | Google Translate (free, no key needed) **default** | — |\r
| `"ai"` | Use `ai` section API (Grok/GPT/Claude/DeepSeek…) | `ai.apiKey` |\r
| `"none"` | No translation, show English as-is | — |\r
\r
### ai (AI Translation)\r
\r
| Field | Type | Default | Validation | Description |\r
|-------|------|---------|------------|-------------|\r
| `apiKey` | string | | | API key for translation |\r
| `model` | string | `"grok-4.1-fast"` | | Model name (any OpenAI-compatible) |\r
| `baseUrl` | string | `"https://api.x.ai/v1"` | must start with `http(s)://` | API endpoint |\r
\r
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.\r
\r
### discord\r
\r
| Field | Type | Default | Description |\r
|-------|------|---------|-------------|\r
| `webhookUrl` | string | `""` | Discord webhook URL (simple mode) |\r
| `botToken` | string | `""` | Discord bot token (advanced mode) |\r
| `channelId` | string | `""` | Discord channel ID (required for bot mode) |\r
\r
Use **either** `webhookUrl` **or** `botToken` + `channelId`, not both.\r
\r
### telegram\r
\r
| Field | Type | Default | Description |\r
|-------|------|---------|-------------|\r
| `enabled` | boolean | `false` | Enable Telegram notifications |\r
| `botToken` | string | `""` | Telegram bot token from @BotFather |\r
| `chatId` | string | `""` | Target chat/group/channel ID |\r
\r
### dashboard\r
\r
| Field | Type | Default | Validation | Description |\r
|-------|------|---------|------------|-------------|\r
| `port` | number | `3848` | 1024-65535 | HTTP server port (restart required) |\r
| `password` | string | `""` | | Access password (empty = no auth) |\r
\r
---\r
\r
## Common Workflows\r
\r
### Check what's currently running\r
\r
```bash\r
curl -s http://localhost:3848/api/status | jq 'to_entries[] | select(.value.active) | .key'\r
```\r
\r
### Enable a source and verify\r
\r
```bash\r
# Enable Jin10\r
curl -s -X POST http://localhost:3848/api/config \\r
-H "Content-Type: application/json" \\r
-d '{"jin10": {"enabled": true, "pollIntervalMs": 15000}}'\r
\r
# Verify it's active\r
curl -s http://localhost:3848/api/status | jq '.jin10'\r
```\r
\r
### Set up Discord + Telegram dual push\r
\r
```bash\r
curl -s -X POST http://localhost:3848/api/config \\r
-H "Content-Type: application/json" \\r
-d '{\r
"discord": {"webhookUrl": "https://discord.com/api/webhooks/..."},\r
"telegram": {"enabled": true, "botToken": "123456:ABC-DEF", "chatId": "-1001234567890"}\r
}'\r
```\r
\r
### Add a new RSS feed (without losing existing ones)\r
\r
**IMPORTANT:** `rssFeeds` is an array. POSTing it replaces the entire list. You must GET first, append, then POST back.\r
\r
**Step 1 — Get current feeds:**\r
\r
```bash\r
curl -s http://localhost:3848/api/config | jq '.rssFeeds'\r
```\r
\r
**Step 2 — POST the full array with the new feed appended:**\r
\r
```bash\r
# Example: existing feeds are BlockTempo and PTS News, adding CoinDesk\r
curl -s -X POST http://localhost:3848/api/config \\r
-H "Content-Type: application/json" \\r
-d '{"rssFeeds": [\r
{"enabled": true, "name": "BlockTempo", "feedUrl": "https://www.blocktempo.com/feed/", "pollIntervalMs": 300000, "color": 16746496},\r
{"enabled": true, "name": "PTS News", "feedUrl": "https://news.pts.org.tw/xml/newsfeed.xml", "pollIntervalMs": 300000, "color": 3447003},\r
{"enabled": true, "name": "CoinDesk", "feedUrl": "https://www.coindesk.com/arc/outboundfeeds/rss/?outputType=xml", "pollIntervalMs": 300000, "color": 2067276}\r
]}'\r
```\r
\r
> Same pattern applies when removing or editing an RSS feed — always send the complete updated array.\r
\r
### Remove an RSS feed\r
\r
GET current list, remove the target, POST back the remaining array.\r
\r
```bash\r
# Get current feeds, then POST without the one you want to remove\r
curl -s http://localhost:3848/api/config | jq '.rssFeeds'\r
# POST back the array minus the removed feed\r
curl -s -X POST http://localhost:3848/api/config \\r
-H "Content-Type: application/json" \\r
-d '{"rssFeeds": [\r
{"enabled": true, "name": "BlockTempo", "feedUrl": "https://www.blocktempo.com/feed/", "pollIntervalMs": 300000, "color": 16746496}\r
]}'\r
```\r
\r
### Add an item to any array field (general pattern)\r
\r
When the user says "also add X", always follow GET → modify → POST:\r
\r
```bash\r
# Step 1: GET current value\r
CURRENT=$(curl -s http://localhost:3848/api/config | jq '.polymarket.tagIds')\r
# Example result: [21, 120]\r
\r
# Step 2: Append and POST back\r
# Adding Sports (100639) to existing [21, 120]\r
curl -s -X POST http://localhost:3848/api/config \\r
-H "Content-Type: application/json" \\r
-d '{"polymarket": {"tagIds": [21, 120, 100639]}}'\r
```\r
\r
Same pattern applies to `opennews.signals`, `opennews.coins`, `opennews.engineTypes`, `polymarket.excludeTagIds`.\r
\r
### Monitor high-impact crypto news only\r
\r
```bash\r
curl -s -X POST http://localhost:3848/api/config \\r
-H "Content-Type: application/json" \\r
-d '{"opennews": {"enabled": true, "minScore": 80, "signals": ["long", "short"], "coins": ["BTC", "ETH", "SOL"], "engineTypes": ["news", "listing"]}}'\r
```\r
\r
### Track new KOL and verify\r
\r
```bash\r
# Add\r
curl -s -X POST http://localhost:3848/api/kols \\r
-H "Content-Type: application/json" \\r
-d '{"action": "add", "username": "VitalikButerin"}'\r
\r
# List all\r
curl -s -X POST http://localhost:3848/api/kols \\r
-H "Content-Type: application/json" \\r
-d '{"action": "list"}'\r
```\r
\r
## Important Rules\r
\r
### Array fields are REPLACED, never merged\r
\r
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.\r
\r
**Array fields that require GET-first when adding/removing items:**\r
\r
| Field | Example "add" intent |\r
|-------|---------------------|\r
| `rssFeeds` | "Add CoinDesk RSS" — GET current feeds, append, POST full array |\r
| `polymarket.tagIds` | "Also track Sports" — GET current tagIds, append `100639`, POST |\r
| `polymarket.excludeTagIds` | "Also exclude Culture" — same pattern |\r
| `opennews.signals` | "Also show long signals" — GET, append `"long"`, POST |\r
| `opennews.coins` | "Also track SOL" — GET, append `"SOL"`, POST |\r
| `opennews.engineTypes` | "Also include listings" — GET, append `"listing"`, POST |\r
\r
**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.\r
\r
**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.\r
\r
### Other rules\r
\r
1. **Object sections support partial update.** You can POST just `{"jin10": {"enabled": false}}` without affecting other jin10 fields or other sections.\r
2. **Sensitive fields are redacted** in GET responses as `"••••••"`. When POSTing, redacted values are automatically preserved (not overwritten).\r
3. **All changes are hot-reloaded** — no restart needed, except `dashboard.port`.\r
4. The `x6551.token` is shared between X tweet monitor and OpenNews.\r
5. Get your 6551 API token at https://6551.io/mcp\r
\r
## Error Responses\r
\r
| HTTP Status | Body | Cause |\r
|-------------|------|-------|\r
| 401 | `{ "ok": false, "error": "Unauthorized" }` | Missing or wrong `?pw=` password |\r
| 400 | `{ "ok": false, "errors": [...] }` | Validation failed (array of error strings) |\r
| 400 | `{ "ok": false, "error": "Invalid JSON" }` | Malformed request body |\r
| 404 | `{ "error": "Not found" }` | Unknown API route |\r
- Make sure OpenClaw is installed (local or Docker)
- Run the install command in chat:
/install buzz - After installation, invoke the skill by name or use
/buzz - Provide required inputs per the skill's parameter spec and get structured output
What is Buzz?
Real-time news aggregator with Discord & Telegram push. Manage Jin10, BlockBeats, RSS, X KOLs, Polymarket, OpenNews via REST API. It is an AI Agent Skill for Claude Code / OpenClaw, with 389 downloads so far.
How do I install Buzz?
Run "/install buzz" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.
Is Buzz free?
Yes, Buzz is completely free (open-source). You can download, install and use it at no cost.
Which platforms does Buzz support?
Buzz is cross-platform and runs anywhere OpenClaw / Claude Code is available (darwin, linux, win32).
Who created Buzz?
It is built and maintained by zxcnny930 (@zxcnny930); the current version is v1.1.1.