npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

echofox

v1.16.0

Published

A production-grade WhatsApp bot built on Baileys 7.x — typed, observable, scalable.

Readme

🦊 EchoFox

A production-grade WhatsApp bot built on Baileys 7.x — typed, observable, scalable, and friendly to extend.

License: AGPL v3 Node ≥20 Baileys 7.0.0-rc13 npm version Docker Hub GHCR CI Docs

⚠️ Please read DISCLAIMER.md before using. Running an unofficial WhatsApp client may violate WhatsApp's Terms of Service and can result in your number being banned. Use a number you can afford to lose.


✨ Features

Core

  • 🔌 Baileys 7.x with the recommended retry, group-metadata, and signal-key caches wired in
  • 🧩 Folder-based command registry with hot-reload, alias resolution, and auto-skip of commands missing API keys
  • 📦 Pluggable store backend — SQLite (default), Postgres, MongoDB, or Redis
  • 🔑 Pluggable auth backend — multi-file (default), Redis, or SQLite
  • 🆔 Login via QR or pairing code
  • 📊 Built-in web dashboard at :3001/dashboard (React-based, with live stats + 11 tabs)
  • 🚦 Per-chat queue for back-pressure
  • ❤️ Health & metrics at GET /healthz and GET /metrics (Prometheus)
  • 📝 Structured logging via Pino
  • 🛡️ Built-in middleware for rate-limiting and concurrency control
  • 🔄 Supervisor + worker model with exponential-backoff restart
  • 🌐 Dual prefix. for users, $ for admins
  • 🧪 Zod-validated config with legacy support

AI service

  • 🤖 4 LLM providers out of the box: OpenAI, Google Gemini, Anthropic Claude, and local Ollama
  • 🛠️ 12 intel-focused tools — VirusTotal, AlienVault OTX, GitHub releases/advisories, Wikipedia, SSRF-guarded fetch_url, plus 5 read-only WhatsApp store queries
  • 🎭 Personasthreat-intel (default, security-focused) / general / custom
  • 🧠 20-turn rolling memory per chat, persisted across restarts
  • Per-chat opt-in — no surprise replies; users explicitly enable with .ai on
  • 💰 Hard daily USD cost cap with per-provider pricing table; rate limits 30/user/hour + 100/chat/day

Telegram log bridge

  • 📡 Outbound-only mirror of WhatsApp log channels (syslogs, botLogs, errLogs, …) to Telegram chats/channels
  • 🔌 Zero new dependencies — raw HTTPS to api.telegram.org over the existing circuit-breaker
  • 2-second batching for info-level logs; error/fatal flushes immediately
  • 🎯 Per-channel routing — different WhatsApp log channels can go to different Telegram destinations
  • 💾 Persistent AI rate-limit counters (v1.3.0) survive bot restarts

Ops polish

  • 🚀 CI/CD auto-releasegit push origin v1.x.x triggers GitHub Release + Docker (GHCR + Docker Hub, multi-arch) + npm publish (with provenance) + Pages deploy in parallel
  • 📚 VitePress docs site auto-deployed to cosm1cbug.github.io/echofox
  • 📊 22 Grafana panels out of the box (defaults + AI + Telegram + Signal Protocol Health)
  • 🚨 2 built-in alert rules: AI cost > 80% of cap, Telegram failure rate > 20% — mirrored to both WhatsApp errLogs AND Telegram
  • 🩹 Signal protocol self-healing (v1.4.2) — auto-recovers from Bad MAC / No session found decryption errors without operator intervention; demotes the noisy ERROR logs to DEBUG

🚀 Quick start

Prerequisites

| | | | -------- | --------------------------------------------------------- | | Node.js | ≥ 20 (tested on 20 + 22 in CI) | | OS | Linux / macOS / Windows 11 | | WhatsApp | A real phone number you can scan a QR / pairing code from |

Install

EchoFox can be installed three ways — pick whichever fits your workflow.

⚡ Option A — npm package (easiest, recommended)

mkdir my-echofox && cd my-echofox
npm init -y
npm install echofox
# Copy the example config from the installed package:
cp node_modules/echofox/src/config.example.js src/config.js   # Linux/macOS
# Or on Windows PowerShell:
# Copy-Item node_modules\echofox\src\config.example.js src\config.js

Latest published version: npm version

🐳 Option B — Docker image (zero-Node-install, multi-arch)

docker pull ghcr.io/cosm1cbug/echofox:latest
# or pin a specific version:
docker pull ghcr.io/cosm1cbug/echofox:1.11.3

Then run with your config mounted in (see Docker section below).

🛠️ Option C — Clone from source (for hacking on the bot itself)

git clone https://github.com/Cosm1cBug/EchoFox.git
cd EchoFox
npm install

Configure

cp src/config.example.js src/config.js
# Edit src/config.js with your details

At minimum set:

Everything else has sensible defaults. See Configuration reference below.

Run

npm start

On first run you'll see a QR code in the terminal. Open WhatsApp on your phone → Settings → Linked Devices → Link a Device → scan it.

Alternatively, pairing code:

// src/config.js
login: { type: 'PAIRING', phoneNumber: '1234567890' }

Then npm start prints an 8-character code; enter it on your phone in the same Linked Devices flow.


🖥️ Dashboard

The bot ships a React-based web dashboard at :3001/dashboard with 12 tabs covering everything the bot tracks.

The tabs:

| Tab | Shows | | ------------- | ------------------------------------------------------------------ | | Overview | uptime, throughput, current load | | Groups | groups the bot is in + per-group activity | | Contacts | known contacts with extended status | | Presence | recently-active users with state icons | | Newsletters | WhatsApp channels the bot follows | | Subscriptions | RSS / AlienVault / VirusTotal subscriptions | | Labels | WA Business labels | | Blocklist | blocked JIDs | | Metrics | full Prometheus metric snapshot | | Diagnostics | self-test report (config, store, auth, network) | | Alerts | active built-in alert rules | | AI | config, cost-cap progress bar, per-day usage table, opted-in chats |

Development

cd dashboard
npm install
npm run dev          # Vite dev server, hot reload

Production

cd dashboard
npm run build        # outputs to dashboard/dist/

Or let the bot serve the bundled version automatically when dashboard.enabled = true.


📦 Built-in commands

Run .menu in WhatsApp to see the live list — 30+ commands across general, download, convert, group, admin, misc, main, tools, user.

Highlights:

| Category | Commands | | ------------ | ------------------------------------------------------------------------------ | | AI (v1.2.0+) | .ai status / on / off / clear / persona / provider / model | | Intel | .virustotal, .alienvault, .thehackersnews, .rss, .github, .vtwatch | | Download | .song, .video, .mediafire, … | | Convert | .sticker, .toimg, .tts | | Group | .add, .kick, .promote, .demote, .link, .approve, … | | Admin ($) | $healthcheck, $serverinfo, $ai-admin stats, … |

See docs/commands.md for the full auto-generated catalogue.


🤖 AI service

Set in src/config.js:

ai: {
  enabled:          true,
  defaultProvider:  'openai',          // openai | gemini | anthropic | local
  model:            'gpt-4o-mini',
  costCapPerDayUsd: 5,
  providers: {
    openai: { apiKey: process.env.OPENAI_API_KEY },
  },
},

Then in any chat:

.ai on
hey echofox, what's the latest on log4j

The bot routes to the selected provider, chains tools (e.g. github_advisories + latest_hackernews + wiki_lookup), cites sources, and stays under your daily cap. Full guide: docs/guide/ai.md or the docs site.


📡 Telegram log bridge

Mirror WhatsApp log channels to Telegram with per-channel routing — outbound-only, no Telegram polling.

telegram: {
  enabled:   true,
  botToken:  process.env.TELEGRAM_BOT_TOKEN,
  routing: {
    syslogs: '@echofox_sys',          // public channel handle
    errLogs: '-1001234567890',        // private group numeric id
    // empty string disables that channel's mirror
  },
  parseMode: 'HTML',
  batchMs:   2000,                    // errors flush instantly
},

Full guide: docs/guide/telegram.md or the docs site.


🏗️ Architecture

                ┌─────────────┐
                │bootstrap.js │  ← supervisor (PM2-like; restarts on crash)
                │:3000/healthz│
                │:3000/metrics│
                └──────┬──────┘
                       │ fork()
                ┌────────▼──────┐
                │  worker.js    │  ← single Baileys socket
                │:3001/dashboard│  ← (when enabled)
                │:3001/metrics  │  ← (store-backed counters)
                └──────┬────────┘
        ┌──────────────┼──────────────────┐
        │              │                  │
   ┌────▼────┐   ┌─────▼─────┐   ┌────────▼────────┐
   │ events/ │   │ commands/ │   │  services/      │
   │ (28)    │   │ (32)      │   │  ai, telegram,  │
   │         │   │           │   │  alertEngine,   │
   │         │   │           │   │  signalHealth,  │
   │         │   │           │   │  metrics, …     │
   └─────────┘   └───────────┘   └─────────────────┘
                                 │
                          ┌──────▼──────┐
                          │  store/     │  SQLite | Postgres | Mongo | Redis
                          │  migrations │
                          └─────────────┘

⚙️ Configuration reference

Edit src/config.js. Every field has a sensible default; you can leave most empty.

Core sections

| Path | Type | Default | Description | | ----------------------- | -------------- | -------------------- | --------------------------------------------------- | | bot.name | string | "EchoFox" | Bot display name | | bot.prefix | string|RegExp | "." | User-command prefix | | bot.adminPrefix | string|RegExp | "$" | Admin-command prefix | | bot.sessionName | string | "@session" | Folder name for WA auth files | | bot.timezone | string | "Asia/Kolkata" | IANA timezone for logs / scheduling | | bot.public | boolean | true | false = admin-only mode | | features.readMessages | boolean | true | Mark incoming msgs as read | | features.readStatus | boolean | true | Mark statuses as read | | features.antiCall | boolean | false | Auto-reject incoming calls | | features.syncHistory | boolean | true | Pull full history on first login | | login.type | enum | "QR" | "QR" or "PAIRING" | | login.phoneNumber | string | "" | Required if type="PAIRING" (digits only) | | auth.method | enum | "MULTIFILE" | "MULTIFILE" / "REDIS" / "SQLITE" | | storeDB.type | enum | "SQLITE" | "SQLITE" / "POSTGRES" / "MONGODB" / "REDIS" | | dashboard.enabled | boolean | false | Built-in web UI | | dashboard.port | number | 3001 | | | dashboard.password | string | "change-me-please" | ⚠️ change this |

AI section

| Path | Type | Default | Description | | ------------------------------- | ------- | -------------------------- | ----------------------------------------------- | | ai.enabled | boolean | false | Master switch | | ai.defaultProvider | enum | 'openai' | openai / gemini / anthropic / local | | ai.model | string | 'gpt-4o-mini' | Provider-specific model name | | ai.maxTokens | number | 800 | Per-response token cap | | ai.costCapPerDayUsd | number | 5 | Hard daily cap — bot refuses to reply past this | | ai.persona | enum | 'threat-intel' | threat-intel / general / custom | | ai.memoryTurns | number | 20 | Rolling memory window (10 user + 10 assistant) | | ai.optInDefault | enum | 'off' | 'on' to auto-enable in every chat | | ai.rateLimitPerUserPerHour | number | 30 | | | ai.rateLimitPerChatPerDay | number | 100 | | | ai.enableToolCalling | boolean | true | | | ai.toolWhitelist[] | array | 12 tools | Which intel tools the model can call | | ai.providers.openai.apiKey | string | '' | | | ai.providers.gemini.apiKey | string | '' | | | ai.providers.anthropic.apiKey | string | '' | | | ai.providers.local.baseUrl | string | 'http://localhost:11434' | Ollama endpoint |

Telegram section

| Path | Type | Default | Description | | ------------------------------------------------------------------------------------ | ------- | -------- | ------------------------------------------------- | | telegram.enabled | boolean | false | | | telegram.botToken | string | '' | from @BotFather | | telegram.routing.{syslogs,botLogs,userLogs,groupUpdates,callLogs,errLogs,movGroup} | string | '' | Telegram chat id or @channel per WA log channel | | telegram.parseMode | enum | 'HTML' | HTML / MarkdownV2 / plain | | telegram.batchMs | number | 2000 | Errors flush instantly regardless | | telegram.maxChunkChars | number | 3800 | Telegram cap is 4096 |

Alerts section

| Path | Type | Default | Description | | ---------------------------------- | ------- | ------------------------------------------------------ | ---------------------------------------------------- | | alerts.enabled | boolean | true | | | alerts.windowMinutes | number | 60 | rolling window | | alerts.minInvocations | number | 10 | need at least N runs to alert | | alerts.failureRateThreshold | number | 0.30 | per-command failure rate trigger | | alerts.rules.aiCostPct | object | {threshold: 0.80, cooldownMinutes: 60} | Fire when daily AI cost reaches this fraction of cap | | alerts.rules.telegramFailureRate | object | {threshold: 0.20, minSends: 10, cooldownMinutes: 30} | Fire when Telegram send-failure rate is high |

Every field can also be set via an environment variable: ECHOFOX_<SECTION>_<CAMELCASEKEY> — e.g. ECHOFOX_APIS_OMDB_APIKEY=xyz, ECHOFOX_STOREDB_TYPE=POSTGRES.

Full configuration guide: docs/config.md.


✍️ Writing your own commands

See CONTRIBUTING.md. TL;DR: drop a .js file in src/commands/<category>/:

module.exports = {
  name: 'hello',
  alias: ['hi'],
  desc: 'Says hello',
  category: 'general',
  cooldown: 3,
  async start(sock, m, { ctx, args, text, config }) {
    await ctx.reply(`Hello ${ctx.pushName || 'friend'}!`);
  },
};

Hot reload picks it up immediately. The contract test (npm test) verifies every command's shape and detects name/alias collisions across the whole tree.


📊 Observability

curl http://localhost:3000/healthz       # supervisor health
curl http://localhost:3000/metrics       # supervisor + Node.js defaults
curl http://localhost:3001/metrics       # store-backed counters

Prometheus metrics exposed (28 counters + 9 gauges across 2 endpoints):

| Endpoint | Metric | Type | Description | | -------- | ------------------------------------------ | ------- | ------------------------------ | | :3000 | echofox_worker_up | gauge | 1 if the worker is alive | | :3000 | echofox_worker_restarts_total | counter | Cumulative supervisor restarts | | :3001 | echofox_messages_received_total | counter | Inbound messages | | :3001 | echofox_commands_total | counter | Command invocations | | :3001 | echofox_ai_chat_requests_total | counter | AI chat requests | | :3001 | echofox_ai_tokens_prompt_total | counter | Prompt tokens consumed | | :3001 | echofox_ai_tokens_completion_total | counter | Completion tokens consumed | | :3001 | echofox_ai_cost_usd_today | gauge | Today's AI spend | | :3001 | echofox_telegram_forwards_total | counter | Telegram log forwards | | :3001 | echofox_telegram_send_failures_total | counter | Telegram send failures | | :3001 | echofox_signal_decryption_failures_total | counter | Baileys decryption errors | | :3001 | echofox_signal_session_recoveries_total | counter | Auto-triggered session resets |

…plus 18 more. Full list at src/store/schema/stats.js.

Grafana dashboard JSON: docker/grafana/dashboards/echofox-overview.json — 22 panels organised in 3 sections (core process metrics, AI v1.2+, Telegram v1.3+, Signal Protocol Health v1.4.2+). Auto-provisioned by the Compose observability profile.


🐳 Docker

One-liner

docker run -d --name echofox \
  -p 3000:3000 -p 3001:3001 \
  -v echofox-data:/app/src/store/runtime \
  -v echofox-session:/app/src/@session \
  -e ECHOFOX_BOT_TIMEZONE=Asia/Kolkata \
  cosm1cbug/echofox:latest

Tag scheme:

  • :1.4.2, :1.3.0, etc. — precise (immutable)
  • :1.4, :1.3, :1.2 — major.minor (auto-updates with patches)
  • :latest — always newest stable
  • :sha-abc1234 — per-commit immutable tag

Available on both GHCR and Docker Hub.

Docker Compose

# Bot only:
docker compose up -d

# With Prometheus + Grafana:
docker compose --profile observability up -d
# → Grafana at http://localhost:3001 (admin / changeme)

Full guides


🚀 Releasing a new version (maintainers)

Tag-driven, fully automated:

# 1. Bump version
npm version patch              # or minor / major
# 2. Update CHANGELOG.md + write RELEASE_NOTES_v<v>.md
git add . && git commit -m "chore(release): v$(node -p require\('./package.json'\).version)"
git push origin main
# 3. Tag — fires 4 workflows in parallel
git tag v$(node -p "require('./package.json').version")
git push origin --tags

Within ~5 minutes:

  • ✅ GitHub Release with RELEASE_NOTES_v<v>.md body + source tarball
  • ✅ Multi-arch Docker images on GHCR + Docker Hub
  • ✅ npm publish with provenance (SLSA attestation)
  • ✅ Docs site deploy to GitHub Pages

Required secrets (all optional): NPM_TOKEN, DOCKERHUB_USERNAME, DOCKERHUB_TOKEN. See docs/deploy/ci-cd.md.


🤝 Contributing

Pull requests welcome! See CONTRIBUTING.md.

CI gates every PR with:

  • ESLint + Prettier
  • 147 automated tests (Node 20 + 22 matrix)
  • AGPL header check (every .js file must have one)
  • Dashboard TypeScript typecheck
  • TruffleHog secret scan

By participating, you agree to behave kindly and constructively.


🔐 Security

Found a vulnerability? Please report it privately — see SECURITY.md.

Hardening summary:

  • 🔒 Per-chat AI opt-in — no surprise replies
  • 🔒 AI fetch_url SSRF guard — refuses RFC 1918 / link-local / loopback
  • 🔒 Telegram bridge is strictly outbound — no inbound command surface
  • 🔒 API keys never exposed via dashboard or /api/ai/config
  • 🔒 Dashboard /api/* routes Basic-auth gated
  • 🔒 npm published with --provenance for SLSA-style supply-chain attestation
  • 🔒 TruffleHog scans every push for leaked secrets
  • 🔒 Weekly Docker image rebuild for base-image security patches

⭐ Star history

Star History Chart

If EchoFox is useful to you, please ⭐ star the repo — it's the cheapest way to say "this is cool, keep going."


📜 License

Licensed under the GNU Affero General Public License v3.0 or later.

In short: if you run a modified version of EchoFox as a service, you must offer the source of your modifications to the users who interact with it over the network. Third-party attributions in NOTICE.


💖 Acknowledgements

  • Baileys by @PurpShell and contributors — none of this would exist without their reverse-engineering

EchoFox is not affiliated with WhatsApp or Meta. WhatsApp™ is a trademark of WhatsApp LLC.