Music: - #random URL fragment shuffles playlist tracks before enqueuing - Lazy playlist resolution: first 10 tracks resolve immediately, remaining are fetched in a background task - !kept repair re-downloads kept tracks with missing local files - !kept shows [MISSING] marker for tracks without local files - TTS ducking: music ducks when merlin speaks via voice peer, smooth restore after TTS finishes Performance (from profiling): - Connection pool: preload_content=True for SOCKS connection reuse - Pool tuning: 30 pools / 8 connections (up from 20/4) - _PooledResponse wrapper for stdlib-compatible read interface - Iterative _extract_videos (replace 51K-deep recursion with stack) - proxy=False for local SearXNG Voice + multi-bot: - Per-bot voice config lookup ([<username>.voice] in TOML) - Mute detection: skip duck silence when all users muted - Autoplay shuffle deck (no repeats until full cycle) - Seek clamp to track duration (prevent seek-past-end stall) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7.6 KiB
derp - Backlog
Core
- Multi-server support (per-server config, shared plugins)
- Stable plugin API (versioned, breaking change policy)
- Paste overflow (auto-paste long output to FlaskPaste)
- URL shortener integration (shorten URLs in subscription announcements)
- Webhook listener (HTTP endpoint for push events to channels)
- Granular ACLs (per-command: trusted, operator, admin)
LLM Bridge
Goal: let an LLM agent interact with the bot over IRC in real-time, with full machine access (bash, file ops, etc.).
Architecture
Owner addresses the bot on IRC. A bridge daemon reads addressed
messages, feeds them to an LLM with tool access, and writes replies
back through the bot. The bot already has owner config
([bot] owner hostmask patterns) to gate who can trigger LLM
interactions.
IRC -> bot stdout (addressed msgs) -> bridge -> LLM API -> bridge -> bot inbox -> IRC
Approach options (ranked)
-
Claude Code Agent SDK (clean, non-trivial)
- Custom Python agent using
anthropicSDK withtool_use - Define tools: bash exec, file read/write, web fetch
- Persistent conversation memory across messages
- Full control over the event loop -- real-time IRC is natural
- Tradeoff: must implement and maintain tool definitions
- Custom Python agent using
-
Claude Code CLI per-message (simple, stateless)
echo "user said X" | claude --print --allowedTools bash,read,write- Each invocation is a cold start with no conversation memory
- Simple to implement but slow startup, no multi-turn context
- Could pass conversation history via system prompt (fragile)
-
Persistent Claude Code subprocess (hack, fragile)
- Long-running
claudeprocess with stdin/stdout piped - Keeps context across messages within a session
- Not designed for this -- output parsing is brittle
- Session may drift or hit context limits
- Long-running
Bot-side plumbing needed
--llmCLI flag: route logging to file, stdout for addressed msgs_is_addressed(): DM or nick-prefixed messages_is_owner(): only owner hostmasks trigger LLM routing- Inbox file polling (
/tmp/llm-inbox): bridge writes<target> <msg> llm-sendscript: line splitting (400 char), FlaskPaste overflow- Stdout format:
HH:MM [#chan] <nick> text/HH:MM --- status - Only LLM-originated replies echoed to stdout (not all bot output)
Previous attempt (reverted)
The --llm mode was implemented and tested (commit ea6f079, reverted
in 6f1f4b2). The stdout/stdin plumbing worked but Claude Code CLI
cannot act as a real-time daemon -- each tool call is a blocking
round-trip, making interactive IRC conversation impractical. The code
is preserved in git history for reference.
Plugins -- Security/OSINT
emailcheck-- SMTP VRFY/RCPT TO verificationcanary-- canary token generator/trackervirustotal-- hash/URL/IP/domain lookup (free API)abuseipdb-- IP abuse confidence scoring (free tier)jwt-- decode tokens, show claims/expiry, flag weaknessesmac-- OUI vendor lookup (local IEEE database)pastemoni-- monitor paste sites for keywordsinternetdb-- Shodan InternetDB host recon (free, no API key)
Plugins -- Utility
paste-- manual paste to FlaskPasteshorten-- manual URL shorteningcron-- scheduled bot commands on a timer
Teams
- Microsoft Teams adapter via outgoing webhooks
- TeamsBot + TeamsMessage (duck-typed with IRC Message)
- HMAC-SHA256 webhook validation
- Permission tiers via AAD object IDs
- Route
send()through SOCKS5 proxy (bug fix) - Adaptive Cards for richer formatting
- Graph API integration for DMs
- Teams event handlers (member join/leave)
Telegram
- Telegram adapter via long-polling (no SDK)
- TelegramBot + TelegramMessage (duck-typed with IRC Message)
- All HTTP through SOCKS5 proxy
- Message splitting at 4096-char limit
- @botusername suffix stripping in groups
- Permission tiers via user IDs
- Inline keyboard support for interactive replies
- Markdown/HTML formatting mode toggle
- Webhook mode (for setWebhook instead of getUpdates)
Discord
- Discord adapter via WebSocket gateway + REST API (no SDK)
- DiscordBot + DiscordMessage (duck-typed with IRC Message)
- Gateway intents for message content
- Message splitting at 2000-char limit
- Permission tiers via user/role IDs
- Slash command registration (optional)
Matrix
- Matrix adapter via long-poll
/syncendpoint (no SDK) - MatrixBot + MatrixMessage (duck-typed with IRC Message)
- Room-based messaging (rooms map to channels)
- Power levels map to permission tiers
- E2EE support (optional, requires libolm)
XMPP
- XMPP adapter via persistent TCP + XML stanzas (no SDK)
- XMPPBot + XMPPMessage (duck-typed with IRC Message)
- MUC (Multi-User Chat) support -- rooms map to channels
- SASL authentication
- TLS/STARTTLS connection
Performance
- Iterative
_extract_videosin alert.py (51K recursive calls, 6.7s CPU) - Bypass SOCKS5 for local services (FlaskPaste, SearXNG)
- Connection pool tuning (529 SOCKS connections per 25min session)
- Async HTTP client (aiohttp + aiohttp-socks) to avoid blocking executors
- Connection pooling via urllib3 SOCKSProxyManager
- Batch OG fetch via ThreadPoolExecutor
- HTTP opener caching at module level
- Per-backend error tracking with exponential backoff
Mumble
- Mumble adapter via TCP/TLS + protobuf control channel (no SDK)
- MumbleBot + MumbleMessage (duck-typed with IRC Message)
- Text chat only (no voice)
- Channel-based messaging
- Minimal protobuf encoder/decoder (no protobuf dep)
- pymumble transport rewrite (voice + text)
- Music playback (yt-dlp + ffmpeg + Opus)
- Voice STT/TTS (Whisper + Piper)
- Multi-bot with per-bot plugin filtering
- Configurable voice profiles (voice, FX chain)
- Self-mute support (auto mute/unmute around audio)
- Bot audio isolation (ignore own bots in sound callback)
- Pause/unpause with position tracking, stale stream re-download, rewind + fade-in
- Autoplay continuous radio (random kept track, silence-aware, configurable cooldown)
- Periodic resume state persistence (survives hard kills)
- Track duration in
!np(ffprobe), optional!announcetoggle - Direct bot addressing (
merlin: say <text>) - Self-deafen on connect
- Per-channel voice settings (different voice per channel)
- Voice activity log (who spoke, duration, transcript)
Music Discovery
- Last.fm integration (API key, free tier)
!similarcommand -- find similar artists/tracks via Last.fm!tagscommand -- show genre/style tags for current track- Auto-queue similar tracks when autoplay has no kept tracks
- MusicBrainz fallback (no API key, 1 req/sec rate limit)
Slack
- Slack adapter via Socket Mode WebSocket (no SDK)
- SlackBot + SlackMessage (duck-typed with IRC Message)
- OAuth token + WebSocket for events
- Channel/DM messaging
- Permission tiers via user IDs
Mattermost
- Mattermost adapter via WebSocket API (no SDK)
- MattermostBot + MattermostMessage (duck-typed with IRC Message)
- Self-hosted Slack alternative
- Channel/DM messaging
Bluesky
- Bluesky adapter via AT Protocol firehose + REST API (no SDK)
- BlueskyBot + BlueskyMessage (duck-typed with IRC Message)
- Mention-based command dispatch
- Post/reply via
com.atproto.repo.createRecord
Testing
- Plugin command unit tests (encode, hash, dns, cidr, defang)
- CI pipeline (Gitea Actions)