Files
loyal_companion/CLAUDE.md
2026-01-14 18:35:57 +01:00

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:

  • pytest with pytest-asyncio for 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.py defines AIProvider abstract class with generate() method
  • services/providers/openai.py, openrouter.py, anthropic.py, gemini.py implement the interface
  • services/ai_service.py is the factory that creates the correct provider based on AI_PROVIDER env var
  • OpenRouter uses OpenAI's client with a different base URL
  • Gemini uses the google-genai SDK

Cog System

Discord functionality is in cogs/:

  • ai_chat.py - @mention handler (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 management
  • services/user_service.py - User CRUD, custom names, facts management
  • services/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 decay
  • relationship_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 time
  • self_awareness_service.py - Bot statistics and self-reflection
  • communication_style_service.py - Learns user communication preferences
  • proactive_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 guild
  • BotOpinion - Topic sentiments and preferences
  • UserRelationship - Per-user relationship scores and metrics
  • UserCommunicationStyle - Learned communication preferences
  • ScheduledEvent - Birthdays, follow-ups, reminders
  • FactAssociation - Cross-user memory links
  • MoodHistory - 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.

The bot can search the web for current information via SearXNG:

  • services/searxng.py provides SearXNGService for web queries
  • ai_chat.py uses 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, and SEARXNG_MAX_RESULTS env vars

Key Design Decisions

  • PersistentConversationManager stores conversations in PostgreSQL when DATABASE_URL is set
  • ConversationManager is the in-memory fallback when database is not configured
  • Long AI responses are split via split_message() in ai_chat.py to respect Discord's 2000 char limit
  • The bot responds only to @mentions via on_message listener
  • 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
  • PortableJSON type in models/base.py allows 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 container
  • SEARXNG_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 !relationship command
  • CMD_MOOD_ENABLED - Enable !mood command
  • CMD_BOTSTATS_ENABLED - Enable !botstats command
  • CMD_OURHISTORY_ENABLED - Enable !ourhistory command
  • CMD_BIRTHDAY_ENABLED - Enable !birthday command
  • CMD_REMEMBER_ENABLED - Enable !remember command
  • CMD_SETNAME_ENABLED - Enable !setname command
  • CMD_WHATDOYOUKNOW_ENABLED - Enable !whatdoyouknow command
  • CMD_FORGETME_ENABLED - Enable !forgetme command

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

  1. Always write tests - New services need corresponding test files in tests/
  2. Update documentation - README.md and relevant docs/ files must be updated
  3. Update CLAUDE.md - Add new services, models, and config options here
  4. Follow existing patterns - Match the style of existing services

Planned Features (In Progress)

The following features are being implemented:

  1. Attachment Pattern Tracking (attachment_service.py)

    • Detect anxious/avoidant/disorganized patterns
    • Adapt responses based on attachment state
    • Track what helps regulate each person
  2. Grief Journey Tracking (grief_service.py)

    • Track grief context and phase
    • Recognize anniversaries and hard dates
    • Adjust support style based on grief phase
  3. Grounding & Coping Tools (grounding_service.py)

    • Breathing exercises, sensory grounding
    • Spiral detection and intervention
    • Session pacing and intensity tracking
  4. Enhanced Support Memory

    • Learn HOW someone wants to be supported
    • Track effective vs ineffective approaches
    • Remember comfort topics for breaks
  5. Communication Style Matching

    • Energy matching (playful vs serious)
    • Directness calibration
    • Real-time tone adaptation