9.8 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Build & Run Commands
# Install dependencies
pip install -r requirements.txt
# Install in development mode (required for testing)
pip install -e .
# Run the bot (requires .env with DISCORD_TOKEN and AI provider key)
python -m loyal_companion
# Run with Docker (includes PostgreSQL)
docker-compose up -d
# Syntax check all Python files
python -m py_compile src/loyal_companion/**/*.py
Testing
# Install dev dependencies
pip install -e ".[dev]"
# Run all tests
python -m pytest tests/ -v
# Run tests with coverage
python -m pytest tests/ --cov=loyal_companion --cov-report=term-missing
# Run specific test file
python -m pytest tests/test_models.py -v
# Run specific test class
python -m pytest tests/test_services.py::TestMoodService -v
The test suite uses:
pytestwithpytest-asynciofor async test support- SQLite in-memory database for testing (via
aiosqlite) - Mock fixtures for Discord objects and AI providers in
tests/conftest.py
Architecture
Loyal Companion is a Discord bot companion for those who love deeply and feel intensely. It features a "Living AI" system called Bartender - a wise, steady presence who listens without judgment, understands attachment theory, and knows when to offer perspective versus when to just hold space.
Provider Pattern
The AI system uses a provider abstraction pattern:
services/providers/base.pydefinesAIProviderabstract class withgenerate()methodservices/providers/openai.py,openrouter.py,anthropic.py,gemini.pyimplement the interfaceservices/ai_service.pyis the factory that creates the correct provider based onAI_PROVIDERenv var- OpenRouter uses OpenAI's client with a different base URL
- Gemini uses the
google-genaiSDK
Cog System
Discord functionality is in cogs/:
ai_chat.py-@mentionhandler (responds when bot is mentioned)memory.py- Memory management commands (!setname,!remember, etc.)status.py- Bot health and status commands
Cogs are auto-loaded by bot.py from the cogs/ directory.
Database & Memory System
The bot uses PostgreSQL for persistent memory (optional, falls back to in-memory):
models/- SQLAlchemy models (User, UserFact, Conversation, Message, Guild, GuildMember)models/living_ai.py- Living AI models (BotState, BotOpinion, UserRelationship, etc.)services/database.py- Connection pool and async session managementservices/user_service.py- User CRUD, custom names, facts managementservices/persistent_conversation.py- Database-backed conversation history
Key features:
- Custom names: Set preferred names for users so the bot knows "who is who"
- User facts: Bot remembers things about users (hobbies, preferences, attachment patterns, grief context)
- Persistent conversations: Chat history survives restarts
- Conversation timeout: New conversation starts after 60 minutes of inactivity
Living AI System
The bot implements a "Living AI" system with emotional depth and relationship tracking:
Services (services/)
mood_service.py- Valence-arousal mood model with time decayrelationship_service.py- Relationship scoring (new face to close friend)fact_extraction_service.py- Autonomous fact learning from conversations (including attachment patterns, grief context, coping mechanisms)opinion_service.py- Bot develops opinions on topics over timeself_awareness_service.py- Bot statistics and self-reflectioncommunication_style_service.py- Learns user communication preferencesproactive_service.py- Scheduled events (birthdays, follow-ups)association_service.py- Cross-user memory associations
Models (models/living_ai.py)
BotState- Global mood state and statistics per guildBotOpinion- Topic sentiments and preferencesUserRelationship- Per-user relationship scores and metricsUserCommunicationStyle- Learned communication preferencesScheduledEvent- Birthdays, follow-ups, remindersFactAssociation- Cross-user memory linksMoodHistory- Mood changes over time
Mood System
Uses a valence-arousal model:
- Valence: -1 (sad) to +1 (happy)
- Arousal: -1 (calm) to +1 (excited)
- Labels: excited, happy, calm, neutral, bored, annoyed, curious
- Time decay: Mood gradually returns to neutral (slower decay = steadier presence)
Relationship Levels
- New Face (0-20): Warm but observant - "Pull up a seat" energy
- Getting to Know You (21-40): Building trust, remembering details
- Regular (41-60): Comfortable familiarity - "Your usual?"
- Good Friend (61-80): Real trust, can be honest even when hard
- Close Friend (81-100): Deep bond, full honesty, reflects patterns with love
Configuration
All config flows through config.py using pydantic-settings. The settings singleton is created at module load, so env vars must be set before importing.
Web Search
The bot can search the web for current information via SearXNG:
services/searxng.pyprovidesSearXNGServicefor web queriesai_chat.pyuses a two-step approach: first asks AI if search is needed, then provides results as context- Search is triggered automatically when the AI determines the query needs current information
- Configured via
SEARXNG_URL,SEARXNG_ENABLED, andSEARXNG_MAX_RESULTSenv vars
Key Design Decisions
PersistentConversationManagerstores conversations in PostgreSQL whenDATABASE_URLis setConversationManageris the in-memory fallback when database is not configured- Long AI responses are split via
split_message()inai_chat.pyto respect Discord's 2000 char limit - The bot responds only to @mentions via
on_messagelistener - Web search uses AI to decide when to search, avoiding unnecessary API calls for general knowledge questions
- User context (custom name + known facts) is included in AI prompts for personalized responses
PortableJSONtype inmodels/base.pyallows models to work with both PostgreSQL (JSONB) and SQLite (JSON)ensure_utc()helper handles timezone-naive datetimes from SQLite
Environment Variables
Required: DISCORD_TOKEN, plus one of OPENAI_API_KEY, OPENROUTER_API_KEY, ANTHROPIC_API_KEY, or GEMINI_API_KEY depending on AI_PROVIDER setting.
Optional:
DATABASE_URL- PostgreSQL connection string (e.g.,postgresql+asyncpg://user:pass@host:5432/db)POSTGRES_PASSWORD- Used by docker-compose for the PostgreSQL containerSEARXNG_URL- SearXNG instance URL for web search capability
Living AI Configuration
LIVING_AI_ENABLED- Master switch for Living AI features (default: true)MOOD_ENABLED- Enable mood system (default: true)RELATIONSHIP_ENABLED- Enable relationship tracking (default: true)FACT_EXTRACTION_ENABLED- Enable autonomous fact extraction (default: true)FACT_EXTRACTION_RATE- Probability of extracting facts (default: 0.4)PROACTIVE_ENABLED- Enable proactive messages (default: true)CROSS_USER_ENABLED- Enable cross-user memory associations (default: false)OPINION_FORMATION_ENABLED- Enable bot opinion formation (default: true)STYLE_LEARNING_ENABLED- Enable communication style learning (default: true)MOOD_DECAY_RATE- How fast mood returns to neutral per hour (default: 0.05)
Command Toggles
COMMANDS_ENABLED- Master switch for all commands (default: true)CMD_RELATIONSHIP_ENABLED- Enable!relationshipcommandCMD_MOOD_ENABLED- Enable!moodcommandCMD_BOTSTATS_ENABLED- Enable!botstatscommandCMD_OURHISTORY_ENABLED- Enable!ourhistorycommandCMD_BIRTHDAY_ENABLED- Enable!birthdaycommandCMD_REMEMBER_ENABLED- Enable!remembercommandCMD_SETNAME_ENABLED- Enable!setnamecommandCMD_WHATDOYOUKNOW_ENABLED- Enable!whatdoyouknowcommandCMD_FORGETME_ENABLED- Enable!forgetmecommand
Commands
User commands
!setname <name>- Set your preferred name!clearname- Reset to Discord display name!remember <fact>- Tell the bot something about you!whatdoyouknow- See what the bot remembers about you!forgetme- Clear all facts about you!relationship- See your relationship level with the bot!mood- See the bot's current emotional state!botstats- Bot shares its self-awareness statistics!ourhistory- See your history with the bot!birthday <date>- Set your birthday for the bot to remember
Admin commands
!setusername @user <name>- Set name for another user!teachbot @user <fact>- Add a fact about a user
Development Guidelines
When Adding New Features
- Always write tests - New services need corresponding test files in
tests/ - Update documentation - README.md and relevant docs/ files must be updated
- Update CLAUDE.md - Add new services, models, and config options here
- Follow existing patterns - Match the style of existing services
Planned Features (In Progress)
The following features are being implemented:
-
Attachment Pattern Tracking (
attachment_service.py)- Detect anxious/avoidant/disorganized patterns
- Adapt responses based on attachment state
- Track what helps regulate each person
-
Grief Journey Tracking (
grief_service.py)- Track grief context and phase
- Recognize anniversaries and hard dates
- Adjust support style based on grief phase
-
Grounding & Coping Tools (
grounding_service.py)- Breathing exercises, sensory grounding
- Spiral detection and intervention
- Session pacing and intensity tracking
-
Enhanced Support Memory
- Learn HOW someone wants to be supported
- Track effective vs ineffective approaches
- Remember comfort topics for breaks
-
Communication Style Matching
- Energy matching (playful vs serious)
- Directness calibration
- Real-time tone adaptation