SDK-first Discord bot with chat, shitposts, and voice pipeline.
Project description
Clanker9000
SDK-first Discord bot with chat, voice pipeline, shitposts, and a standalone CLI.
Clanker9000 separates a reusable SDK (clanker) from its Discord host (clanker_bot). Build multi-personality bots with LLM chat, voice transcription, TTS output, and meme generation — all with pluggable provider abstractions. Use the SDK standalone via the CLI without any Discord infrastructure.
Features
- Multi-Persona Support - YAML-configured bot personalities with custom system prompts and voice settings
- Voice Pipeline - Real-time voice activity detection (Silero VAD), chunking, idle flush, and speech-to-text
- Voice Resilience - Keepalive packets, automatic reconnection, and actor-based voice management
- CLI Interface - Chat, speak, transcribe, and generate memes from the command line
- Provider Architecture - Pluggable adapters for LLM (OpenAI, Anthropic), STT (Whisper), TTS (ElevenLabs), and image generation (Memegen)
- Shitpost Generator - Context-aware meme generation with ephemeral preview/post/regenerate workflow
- VC Monitoring - Auto-leave when alone, nudge-to-join when humans gather
- Feedback Persistence - Track user interactions (accepted/rejected/regenerated) with SQLite via sqlc
- Structured Logging - File-based rotation, JSON format, voice-specific log levels
Discord Commands
| Command | Description |
|---|---|
/chat <prompt> |
Chat with Clanker |
/speak <prompt> |
Chat with TTS audio response |
/shitpost [n] [guidance] |
Generate meme previews with Post/Regenerate/Dismiss buttons |
/join |
Join your voice channel for transcription |
/leave |
Leave the current voice channel |
/transcript |
Show recent voice transcripts (ephemeral) |
CLI Commands
clanker chat "What is the meaning of life?" # Chat with the LLM
clanker speak "Hello world" -o hello.mp3 # Generate TTS audio
clanker transcribe audio.wav # Transcribe audio file
clanker shitpost --guidance "programming" # Generate a shitpost
clanker meme --guidance "cats" # Generate a meme image
clanker config show # Show active configuration
Use --config path/to/config.yaml and --persona <id> to control persona selection.
Installation
Prerequisites
- Python 3.12+
- uv package manager
Install from GitHub
# Install the CLI tool (lightweight — SDK + CLI only)
uv tool install git+https://github.com/safurrier/clanker.git
# Install as a library
uv pip install git+https://github.com/safurrier/clanker.git
# Install with Discord bot support
uv pip install "clanker9000[bot] @ git+https://github.com/safurrier/clanker.git"
# Install with everything (bot + voice)
uv pip install "clanker9000[bot,voice] @ git+https://github.com/safurrier/clanker.git"
Local Development Setup
# Install all dependencies (including bot, voice, dev)
make setup
# Run quality checks
make check
Environment Variables
# Required for LLM and STT (when using OpenAI provider)
export OPENAI_API_KEY="sk-..."
# Required for LLM (when using Anthropic provider)
export ANTHROPIC_API_KEY="sk-ant-..."
# Required for Discord bot
export DISCORD_TOKEN="..."
# Required for TTS
export ELEVENLABS_API_KEY="..."
# Optional
export CLANKER_CONFIG_PATH="./config.yaml" # Custom config path
export VOICE_DEBUG=1 # Enable voice debug capture
export VOICE_DEBUG_DIR="./voice_debug" # Debug output directory
export LOG_DIR="./logs" # Enable file logging (JSON, rotated)
export LOG_LEVEL="INFO" # Base log level
export VOICE_LOG_LEVEL="INFO" # Voice-specific log level
export DATABASE_URL="sqlite:///data/clanker.db" # Database path
export USE_VOICE_ACTOR=1 # Enable actor-based voice management
Quick Start
SDK Usage
from clanker.models import Context, Message, Persona
from clanker.providers.openai.llm import OpenAILLM
from clanker.respond import respond
# Create a persona
persona = Persona(
id="assistant",
display_name="Helper",
system_prompt="You are a helpful assistant.",
)
# Build context
context = Context(
request_id="req-001",
user_id=0,
guild_id=None,
channel_id=0,
persona=persona,
messages=[Message(role="user", content="Hello!")],
metadata={},
)
# Generate response
llm = OpenAILLM(api_key="sk-...")
response, audio = await respond(context, llm=llm)
print(response.content)
Voice Transcription
from clanker.providers.openai.stt import OpenAISTT
stt = OpenAISTT(api_key="sk-...")
with open("audio.wav", "rb") as f:
audio_bytes = f.read()
transcript = await stt.transcribe(audio_bytes)
print(transcript)
Run the Discord Bot
Requires the [bot] extra (included by make setup):
make run
# Or directly:
python -m clanker_bot.main
# With custom config:
CLANKER_CONFIG_PATH=./my-config.yaml make run
Configuration
Create a config.yaml file:
providers:
llm: openai # or: anthropic
stt: openai
tts: elevenlabs
image: memegen
personas:
- id: clanker
display_name: Clanker9000
system_prompt: |
You are Clanker9000, a witty and slightly sarcastic Discord bot.
Keep responses concise and entertaining.
tts_voice: "Rachel"
- id: helper
display_name: Helper Bot
system_prompt: |
You are a helpful assistant. Be clear and informative.
tts_voice: "Alice"
default_persona: clanker
Project Structure
src/
clanker/ # Core SDK (no Discord dependencies)
config/ # Configuration loading (YAML)
providers/ # Pluggable provider adapters
openai/ # LLM (GPT) and STT (Whisper)
anthropic/ # LLM (Claude)
elevenlabs/ # TTS
memegen/ # Meme image generation
audio_utils.py # Stereo-to-mono, resampling
base.py # Protocol definitions (LLM, STT, TTS, ImageGen)
factory.py # Provider construction with lazy env-var resolution
shitposts/ # Template-based meme content generation
voice/ # Voice processing pipeline
vad.py # Voice activity detection (Silero/Energy)
chunker.py # Audio chunking with idle flush
formats.py # AudioFormat abstraction
worker.py # Transcription orchestration
debug/ # Debug capture system
models.py # Domain models (Context, Persona, Message)
respond.py # Core response orchestration
clanker_cli/ # Click-based CLI (consumes SDK)
commands/ # chat, speak, transcribe, shitpost, meme, config
main.py # CLI entry point and shared context
clanker_bot/ # Discord bot host
command_handlers/ # /chat, /speak, /shitpost, /join, /leave, etc.
cogs/ # Discord cogs (vc_monitor)
persistence/ # Feedback persistence (sqlc-gen-python + SQLite)
views/ # Discord UI views (shitpost preview)
voice_actor.py # Actor-based voice management
voice_ingest.py # Voice receive integration
voice_resilience.py # Keepalive and reconnection
logging_config.py # Structured logging setup
commands.py # Slash command registration
health.py # Health endpoint
main.py # Bot entry point
tests/ # Test suite
cli/ # CLI command tests (CliRunner + fakes)
network/ # Integration tests (require API keys)
test_*.py # Unit tests
Development
make check # Run all checks (lint, format, test, typecheck)
make test # Run tests (excludes network tests)
make lint # Ruff linting with auto-fix
make format # Ruff formatting
make ty # Type checking with ty
make setup # Install all dependencies with uv
make run # Run the Discord bot
Voice Support
Voice features require additional dependencies:
uv pip install -e ".[voice]"
Two VAD implementations are available:
| Implementation | Accuracy | Dependencies | Size |
|---|---|---|---|
| SileroVAD (default) | High (ML-based) | torch, numpy | ~500MB |
| EnergyVAD (fallback) | Moderate (RMS) | Built-in | Minimal |
Docker
See docker/README.md for full documentation.
docker-compose up -d
Documentation
Detailed guides in agent_docs/:
- Architecture - System design, data flows, design decisions
- Testing - Testing strategy, fixtures, fakes, markers
- Voice Pipeline - End-to-end voice processing and debugging
- Providers - Provider system and adding new providers
Additional docs in docs/:
License
MIT License - see LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file clanker9000-0.3.0.tar.gz.
File metadata
- Download URL: clanker9000-0.3.0.tar.gz
- Upload date:
- Size: 2.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
64b56d6acc3d75612f2eb0233832b4bd790bd7c3e91371ab23cd5a125f3ea8f4
|
|
| MD5 |
59c483e59f5d293e289816574464ae2f
|
|
| BLAKE2b-256 |
6035cf48a0816b654d8b3df8700c0fc5cdda4aa0f30c6cb0fd30af83cf196b39
|
Provenance
The following attestation bundles were made for clanker9000-0.3.0.tar.gz:
Publisher:
publish.yml on safurrier/clanker
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
clanker9000-0.3.0.tar.gz -
Subject digest:
64b56d6acc3d75612f2eb0233832b4bd790bd7c3e91371ab23cd5a125f3ea8f4 - Sigstore transparency entry: 1005794623
- Sigstore integration time:
-
Permalink:
safurrier/clanker@66b7460d30fb29e4ce31a4ad11018b28664889e0 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/safurrier
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@66b7460d30fb29e4ce31a4ad11018b28664889e0 -
Trigger Event:
release
-
Statement type:
File details
Details for the file clanker9000-0.3.0-py3-none-any.whl.
File metadata
- Download URL: clanker9000-0.3.0-py3-none-any.whl
- Upload date:
- Size: 190.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
92a605ee4ef0fd0dc49c3fa6488ba81ff19ce483b5a81fec1f4bdb19a3eb761b
|
|
| MD5 |
5315b638fcc4b661c9c764808165ce42
|
|
| BLAKE2b-256 |
8848b802e4052ace928769f0386cd85ee0eac3162ae7c0e3c67b6edb05c3d940
|
Provenance
The following attestation bundles were made for clanker9000-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on safurrier/clanker
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
clanker9000-0.3.0-py3-none-any.whl -
Subject digest:
92a605ee4ef0fd0dc49c3fa6488ba81ff19ce483b5a81fec1f4bdb19a3eb761b - Sigstore transparency entry: 1005794652
- Sigstore integration time:
-
Permalink:
safurrier/clanker@66b7460d30fb29e4ce31a4ad11018b28664889e0 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/safurrier
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@66b7460d30fb29e4ce31a4ad11018b28664889e0 -
Trigger Event:
release
-
Statement type: