Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Clanker: Discord Gemini Bot

Multi-turn Discord chatbot using Google Gemini. DM or @mention it in a server. It reads attached files, searches the web, stores per-user memories, and writes daily audit logs. Plain Node.js ESM, no build step, no framework.


Requirements

  • Node.js ≥ 22 (24 LTS recommended; .nvmrc pins 24)
  • ffmpeg + pngquant on PATH (for image processing). The bot still works without them; images are passed through unprocessed.
# Debian/Ubuntu
sudo apt install ffmpeg pngquant
# Termux (Android)
pkg install ffmpeg pngquant

Setup

  1. Discord bot
    • Create an app at https://discord.com/developers/applications
    • Bot tab → Reset Token → copy
    • Enable Message Content Intent under Privileged Gateway Intents
    • OAuth2 → URL Generator → scope bot → permissions: View Channels, Send Messages, Read Message History → add to server
    • DMs work without extra setup. The gateway needs DirectMessages intent + Partials.Channel, both already enabled in bot.js.
  2. Gemini key: https://aistudio.google.com/apikey
  3. Environment
    cp .env.example .env
    # Fill in DISCORD_TOKEN and GEMINI_API_KEY
    # Optional: STATUS_CHANNEL_ID, GEMINI_MODEL, GEMINI_TIMEOUT_MS, ...
  4. Install & run
    npm install
    npm start        # loads .env automatically
    npm run dev      # auto-restart on file change

Commands

Command Description
!search <query> DuckDuckGo web search
!remember <key> <value> Store a fact
!recall <key> Retrieve a stored fact
!forget <key> Delete a stored fact
!memory List all stored facts
!restart Restart the bot (admin, server only)
!help Show this help

Attach text files (.txt, .js, .py, .md, ...) to include them as snippets, or images (.jpg, .png, .webp, .gif, ...) to send them to Gemini. Images at or under 1024px and under the inline byte cap are sent as-is. Small PNGs go through pngquant. Everything else is resized to 1024px and converted to JPEG q3 / WebP q80. Unsupported types return an error listing the skipped file.

Features

  • Context compression: conversation summarized via Gemini after CONTEXT_COMPRESS_AFTER * 2 messages (default 20)
  • Memory: per-user JSON store (atomic writes, main + backup)
  • Skills: loads skills/<name>/SKILL.md and injects keyword-matched hints into the prompt. skills/ is gitignored except .gitkeep. Force-add curated skills before publishing: git add -f skills/<name>.
  • Backpressure: per-channel message serialization, bounded queue (rejects when full), Gemini concurrency semaphore (3 by default)
  • Web search: DuckDuckGo Lite with 10s timeout and 300s cache
  • File handling: text snippets with BOM/encoding detection; image fast-path (header sniff, no subprocess for small images), ffmpeg/pngquant compression, per-file + per-message download budgets enforced before download starts
  • Audit logging: buffered daily JSONL files in logs/, 30-day retention
  • Anti-spam: rate limiting (10 msgs/30s/user), duplicate guard (content + message-id dedup), input sanitization
  • Graceful shutdown: drains queue, flushes memory + audit, 30s force-exit fallback

File Overview

bot.js                 # Entry point: Discord events, per-channel queue, Gemini calls
config.js              # System prompt + env-driven config
commands.js            # Command handlers
rateLimiter.js         # Per-user rate limit + duplicate guard
conversationManager.js # Per-channel history with TTL eviction + GC
memoryStore.js         # Persistent per-user memory (JSON)
auditLogger.js         # Buffered JSONL audit logging
skillLoader.js         # Loads opencode skills, matches by keyword
search.js              # DuckDuckGo Lite search (parse5, 300s cache)
fileHandler.js         # Text/image detection + ffmpeg/pngquant processing

Configuration

All knobs live in config.js with defaults; see .env.example for the full list (timeouts, download caps, memory/conversation/rate-limit/audit limits). Notables:

  • GEMINI_MODEL: defaults to a rolling alias (gemini-flash-lite-latest); pin a concrete model ID when stability matters
  • MAX_DOWNLOAD_SIZE / MAX_TOTAL_DOWNLOAD_BYTES: per-file and per-message attachment caps (10 MB / 50 MB default), host allowlist restricted to Discord CDN. The total budget is reserved up front from Discord-reported sizes, so concurrent downloads can never overshoot it.
  • IMAGE_MAX_DIM (1024): images at/below this size skip re-encoding entirely
  • PNG_COMPRESS_ENABLED: set false to skip pngquant and use ffmpeg for small PNGs

Agent notes

Entry flow per message:

guards (rate/duplicate/capacity/audit) → per-channel queue (messageQueue, semaphore GEMINI_MAX_CONCURRENT=3) → processAttachments (worker pool of 3, runWithConcurrency in bot.js) → prompt build → Gemini → history append → chunked reply.

  • History is NOT the prompt: per-user memory is injected every turn but never stored in history. conversationManager.get() returns a copy; mutate + set() to persist.
  • bot.js has 0% test coverage (Discord client side effects at import). Test pure logic in the module files instead; use the destroy()/stopAutoGC()/clearCache() hooks to avoid timer/cache leaks across test files.
  • Prettier print width is 100; eslint expects 0 errors (no-await-in-loop/no-shadow warnings are accepted).

Deploy

  • Docker: Dockerfile included (node:24-alpine + ffmpeg/pngquant). Data/logs live in the container; set env vars externally.
  • Free hosts: Railway or Fly.io: push repo, set env vars.
  • pm2 (VPS):
    npm install -g pm2
    pm2 start bot.js --name clanker
    pm2 save && pm2 startup

Development

npm test        # node --test tests/
npm run lint    # eslint, 0 errors expected
npm run format  # prettier

CI runs eslint + prettier + npm audit + tests on a Node 22/24 matrix.

data/ and logs/ are gitignored. They hold per-user memories and daily JSONL audit logs with message content. Never force-add them.

License

MIT. See LICENSE.

About

Clanker: Discord Gemini bot, DMs, attachments, memory, skills, audit logs

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages