A production-ready system that adds LLM intelligence with vector memory to your Eggdrop IRC bot using OpenRouter's API.
IRC User → Eggdrop Bot → Local Gateway (Node/TS) → OpenRouter API
↓ ↓
IRC Channel (bot replies) Vector Memory (SQLite)
Flow:
- All channel messages are stored in vector memory for contextual awareness
- When a user mentions your bot (e.g.,
@botnameorbotname:), the bot responds - Eggdrop Tcl script POSTs to local gateway with the query
- Gateway retrieves relevant context from vector memory (recent + semantically similar messages)
- Context + query sent to OpenRouter with system prompt
- LLM generates response with full conversational awareness
- Gateway returns plain text to Eggdrop
- Bot prints reply to channel
Features:
- Vector memory system - Bot remembers all channel conversations, not just direct mentions
- Semantic search - Finds relevant past messages using embeddings (Xenova/all-MiniLM-L6-v2)
- Chronological ordering - Context presented in proper timeline for coherent recall
- Hybrid context - Combines recent messages + semantically similar messages
- Per-user rate limiting (10s cooldown)
- Error handling at every layer
- Free tier model by default (qwen/qwen3-4b:free)
- Configurable message retention (default: 90 days)
- Plain text responses for easy Tcl parsing
git clone https://github.com/splinesreticulating/eggdrop-ai.git
cd eggdrop-aicd gateway
npm install
cp .env.example .envEdit .env and add your OpenRouter API key:
OPENROUTER_API_KEY=sk-or-v1-...Get your API key from: https://openrouter.ai/keys
Setup vector memory system:
# Download and setup sqlite-vec extension (required for vector embeddings)
npm run setupThis downloads the sqlite-vec extension needed for vector similarity search.
Development (with auto-reload):
npm run devProduction:
npm startThe gateway listens on http://127.0.0.1:3042 by default.
Health check:
curl http://127.0.0.1:3042/health
# Should return: OKNote: On first run, the gateway will download the embedding model (~90MB). This takes 10-30 seconds and only happens once.
Requirements:
- Eggdrop 1.8.0+ with
httppackage (standard in modern builds)
Installation:
# Copy the Tcl script to your Eggdrop scripts directory
cp eggdrop/eggdrop-ai.tcl /path/to/eggdrop/scripts/
# Add to eggdrop.conf
echo 'source scripts/eggdrop-ai.tcl' >> /path/to/eggdrop/eggdrop.conf
# Rehash or restart
# In IRC: .rehash
# Or restart: ./eggdrop -m eggdrop.confMention your bot using @botname or botname: (where botname is your actual bot's nickname):
<user> @mybot what is TCP?
<bot> Transmission Control Protocol - reliable, ordered data delivery over networks.
<user> mybot: explain quantum computing
<bot> Computers using quantum mechanics for parallel computation. Still mostly experimental.
<user> @mybot
<bot> user: yes?
Users are rate-limited to prevent spam (10 second cooldown by default):
<user> @mybot test
<bot> Sure!
<user> @mybot another test
<bot> user: please wait 8s
| Variable | Default | Description |
|---|---|---|
OPENROUTER_API_KEY |
(required) | Your OpenRouter API key |
PORT |
3042 |
Gateway HTTP port |
MODEL |
qwen/qwen3-4b:free |
OpenRouter model ID |
REPO_URL |
(optional) | GitHub repo URL for OpenRouter attribution |
DEBUG_LOG_REQUESTS |
false |
Log full message arrays sent to OpenRouter (for debugging context) |
Vector Memory Configuration:
| Variable | Default | Description |
|---|---|---|
MEMORY_ENABLED |
true |
Enable/disable vector memory system |
MEMORY_DB_PATH |
gateway/data/memory.db |
Database file path |
MEMORY_TOP_K |
15 |
Max similar messages to retrieve |
MEMORY_RECENT_COUNT |
5 |
Recent messages to include in context |
MEMORY_RETENTION_DAYS |
90 |
Delete messages older than N days (0 = keep forever) |
Popular free models:
qwen/qwen3-4b:free(default, fast and capable)xiaomi/mimo-v2-flash:free(used in production)qwen/qwen-2.5-7b-instruct:freemeta-llama/llama-3.2-3b-instruct:freegoogle/gemma-2-9b-it:free
See all models: https://openrouter.ai/models?order=newest&supported_parameters=tools
Edit these variables at the top of the script:
set llmbot_gateway "http://127.0.0.1:3042/chat" ;# LLM query endpoint
set llmbot_store_gateway "http://127.0.0.1:3042/store" ;# Memory storage endpoint
set llmbot_timeout 100000 ;# 100 seconds (for slow free tier models)
set llmbot_rate_limit 10 ;# 10 seconds between requests
set llmbot_max_response_size 50000 ;# 50KB max response sizeHow memory works:
- Bot stores ALL channel messages via
/storeendpoint (fire-and-forget) - Bot only responds when directly mentioned (
@botnameorbotname:) - When responding, bot retrieves relevant context from vector memory
- Context includes recent messages + semantically similar past messages
Test LLM query endpoint:
curl -X POST http://127.0.0.1:3042/chat \
-H "Content-Type: application/json" \
-d '{"message":"what is IRC?","user":"testuser","channel":"#test"}'Expected response (plain text):
Internet Relay Chat - real-time text messaging protocol from 1988.
Test memory storage endpoint:
curl -X POST http://127.0.0.1:3042/store \
-H "Content-Type: application/json" \
-d '{"message":"just storing this for context","user":"testuser","channel":"#test"}'Expected response:
Stored
In IRC DCC chat or partyline:
.tcl llmbot_query "testuser" "#test" "hello"-
Check gateway is running:
curl http://127.0.0.1:3042/health
-
Check Eggdrop loaded the script:
.tcl info loaded # Should list eggdrop-ai.tcl -
Check Eggdrop console:
.console +d # Watch for error messages -
Test trigger patterns: The bot responds to mentions using its configured nickname:
@botname <message>botname: <message>
Not:
botname <message>(without @ or colon)
Gateway won't start / exits immediately:
- Missing
OPENROUTER_API_KEYin.env - Missing sqlite-vec extension - run
npm run setup - Gateway validates API key on startup and exits if not configured
"LLM service error":
- Check OpenRouter API status: https://status.openrouter.ai/
- Verify API key is valid
- Check gateway console for error details
"Empty response from LLM":
- Try a different model in
.env - Check OpenRouter rate limits
Memory issues:
- First run downloads embedding model (~90MB, takes 10-30 seconds)
- If memory errors occur, check disk space for
gateway/data/memory.db - To reset memory: stop gateway, delete
gateway/data/memory.db, restart - Disable memory if needed:
MEMORY_ENABLED=falsein.env
Edit llmbot_rate_limit in eggdrop-ai.tcl:
set llmbot_rate_limit 5 ;# Reduce to 5 secondsThe bot's personality is defined in gateway/system-prompt.txt:
You are an IRC bot assistant. Your core traits:
- Only respond when directly addressed
- Extremely concise: 1-2 sentences maximum
- High signal, zero fluff
- No greetings, no emojis, no verbosity
- Direct answers only
- Skip politeness - just deliver information
- If you don't know, say so in 5 words or less
- No internal reasoning - respond directly
You're in an IRC channel where bandwidth and attention are precious. Every word counts.
Edit gateway/system-prompt.txt to customize the bot's behavior. Changes take effect when the gateway is restarted.
npm install -g pm2
cd gateway
pm2 start npm --name eggdrop-ai-gateway -- start
pm2 save
pm2 startup # Auto-start on rebootCreate /etc/systemd/system/eggdrop-ai-gateway.service:
[Unit]
Description=Eggdrop AI LLM Gateway
After=network.target
[Service]
Type=simple
User=eggdrop
WorkingDirectory=/path/to/eggdrop-ai/gateway
ExecStart=/usr/bin/npm start
Restart=on-failure
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl enable eggdrop-ai-gateway
sudo systemctl start eggdrop-ai-gateway
sudo systemctl status eggdrop-ai-gateway- Gateway binds to
127.0.0.1only (localhost) - No authentication needed - only accessible locally
- Keep
OPENROUTER_API_KEYsecret - Monitor token usage on OpenRouter dashboard
- Consider setting up firewall rules
Free tier models are rate-limited by OpenRouter. Monitor usage at: https://openrouter.ai/activity
Tips for staying in free tier:
- Use
qwen/qwen3-4b:free(default) orxiaomi/mimo-v2-flash:free - Keep
max_tokenslow (currently 300) - Rate limiting in Tcl script helps prevent abuse
- Vector memory runs locally (no API costs)
Note: With vector memory, each bot response includes context from past messages, which increases prompt tokens slightly but provides much better responses.
Paid models:
Update MODEL in .env to any OpenRouter model. Costs typically $0.001-0.01 per request.
eggdrop-ai/
├── eggdrop/
│ └── eggdrop-ai.tcl # Eggdrop Tcl script
├── gateway/
│ ├── server.ts # Express gateway service
│ ├── memory.ts # Vector memory system
│ ├── system-prompt.txt # Bot personality/instructions
│ ├── package.json
│ ├── tsconfig.json
│ ├── .env.example
│ ├── .env # Your config (gitignored)
│ └── data/
│ └── memory.db # SQLite vector database
└── README.md
The bot uses a hybrid memory approach:
- Recent messages - Last 5 messages in chronological order
- Similar messages - Top 15 semantically similar messages using vector search
- Chronological ordering - All context sorted by timestamp before sending to LLM
How it works:
- Uses
Xenova/all-MiniLM-L6-v2embedding model (384 dimensions) - Stores messages in SQLite with
sqlite-vecextension for vector similarity search - Embeddings generated async (don't block response)
- Cosine similarity for semantic search
- Automatic cleanup of old messages based on retention policy
To disable memory:
# In gateway/.env
MEMORY_ENABLED=falseTo add more features:
- Logging: Add Winston or Pino for structured logs
- Metrics: Add Prometheus endpoint for monitoring
- Multiple models: Route different triggers to different models
- Custom embeddings: Swap out the embedding model in
memory.ts - Multi-channel isolation: Already supported - memories are per-channel
# In gateway/.env
MODEL=anthropic/claude-3-haiku
# Restart gateway
npm startSee model list: https://openrouter.ai/models
MIT
- OpenRouter Docs: https://openrouter.ai/docs
- Eggdrop Wiki: https://docs.eggheads.org/
- Issues: https://github.com/splinesreticulating/eggdrop-ai/issues