Files
ws-sanctum-chronicler/README.md

11 KiB

The Sanctum Chronicler

A Dockerized Python MVP for an AI stream assistant that monitors Twitch chat, gently guides conversation, stores stream events, and exports a post-stream markdown ledger.

Overview

The Sanctum Chronicler is an intelligent assistant designed to enhance live streaming by:

  • Monitoring real-time chat and stream activity
  • Maintaining a warm, non-intrusive presence during streams
  • Flagging suspicious content and spam patterns
  • Archiving discussion highlights and clip candidates
  • Generating post-stream ledgers and blog ideas

The system uses a multi-mode agent architecture, where different "personas" handle different aspects of stream management:

  • Hearthkeeper - Gently prompts chat when it's quiet
  • Steward - Responds thoughtfully to engagement
  • Warden - Detects suspicious content and spam
  • Librarian - Archives important discussion
  • Scribe - Compiles post-stream ledgers

Architecture

Project Structure

sanctum-agent/
├── app/
│   ├── main.py                 # FastAPI application
│   ├── config.py               # Configuration (pydantic-settings)
│   ├── twitch/
│   │   ├── eventsub.py        # Twitch EventSub client (stub)
│   │   └── chat.py            # Chat message handling (stub)
│   ├── agent/
│   │   ├── orchestrator.py    # Main agent orchestrator
│   │   ├── policies.py        # Behavior policies
│   │   └── modes/
│   │       ├── hearthkeeper.py
│   │       ├── steward.py
│   │       ├── warden.py
│   │       ├── librarian.py
│   │       └── scribe.py
│   ├── memory/
│   │   ├── database.py        # Async SQLAlchemy setup
│   │   ├── models.py          # Database models
│   │   └── repository.py      # Data access layer
│   ├── llm/
│   │   ├── client.py          # Pluggable LLM client
│   │   └── prompts.py         # Prompt templates
│   └── exports/
│       └── markdown.py        # Markdown ledger generation
├── exports/                    # Generated ledgers
├── data/                       # Local data storage
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
├── .env.example
└── README.md

Tech Stack

  • Python 3.12 - Core language
  • FastAPI - REST API framework
  • SQLAlchemy + asyncpg - Async database ORM
  • PostgreSQL - Primary data store
  • Docker & Docker Compose - Containerization
  • Pydantic - Configuration and validation

Key Design Patterns

Agent Modes: Each mode operates independently but shares access to:

  • The LLM client for text generation
  • The database repository for persistence
  • Shared policies for behavior control

Policies: Encapsulate decision logic:

  • ChatActivityPolicy - Tracks inactivity periods
  • ResponseSuppression - Avoids speaking during active chat
  • SuspiciousContentPolicy - Pattern matching for spam/scams

Async Architecture: All I/O operations are non-blocking:

  • Database queries use asyncpg
  • FastAPI endpoints handle concurrent requests
  • LLM calls prepare for real API integration

Setup & Quick Start

Prerequisites

  • Docker & Docker Compose
  • Python 3.12 (for local development)
  • PostgreSQL 16 (or use Docker)

1. Clone Repository

cd ws-sanctum-chronicler

2. Configure Environment

cp .env.example .env
# Edit .env with your settings (Twitch tokens, LLM provider, etc.)

3. Start Services

docker-compose up --build

The API will be available at http://localhost:8000

4. Test the API

Health Check:

curl http://localhost:8000/health

Start Session:

curl -X POST http://localhost:8000/admin/session/start \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "channel_name=example_channel"

Send Test Message:

curl -X POST http://localhost:8000/admin/test-message \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "session_id=<SESSION_ID>&username=test_user&message=Hello stream!"

Get Ledger:

curl http://localhost:8000/admin/ledger?session_id=<SESSION_ID>

End Session:

curl -X POST http://localhost:8000/admin/session/end \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "session_id=<SESSION_ID>"

API Endpoints

Health & Status

  • GET /health - Application health check

Session Management

  • POST /admin/session/start?channel_name=<name> - Start stream session
  • POST /admin/session/end?session_id=<id> - End stream session

Testing & Admin

  • POST /admin/test-message?session_id=<id>&username=<user>&message=<msg> - Send test message
  • GET /admin/ledger?session_id=<id> - Retrieve markdown ledger

Configuration

All settings are loaded from environment variables (see .env.example):

Application

  • APP_NAME - Application display name
  • APP_ENV - Environment (development/production)
  • DEBUG - Enable debug logging

Database

  • DATABASE_URL - PostgreSQL connection string
  • DB_PASSWORD - Database password (for docker-compose)

Twitch (Optional - Stubs Present)

  • TWITCH_CLIENT_ID - Twitch OAuth client ID
  • TWITCH_CLIENT_SECRET - Twitch OAuth secret
  • TWITCH_BOT_USERNAME - Bot username
  • TWITCH_CHANNEL_NAME - Channel to monitor

LLM

  • LLM_PROVIDER - Provider: openai, ollama, lm_studio, or empty for mock
  • LLM_BASE_URL - API endpoint (for local providers)
  • LLM_API_KEY - API key (if needed)
  • LLM_MODEL - Model identifier (default: gpt-3.5-turbo)

Export

  • EXPORT_PATH - Directory for ledger exports

Agent Policies

Chat Activity Policy

  • Inactivity Threshold: 15 minutes
  • Hearthkeeper Activation: Sends gentle prompt when no messages for 15+ minutes
  • Human Override: Hearthkeeper stays silent if chat is active (5+ messages/minute)

Response Suppression

  • Active Chat Threshold: 5 messages per minute
  • Behavior: Agent suppresses responses when humans are actively talking
  • Rationale: Respects human conversation and avoids noise

Suspicious Content Detection

Patterns Detected:

  • "join our discord", "discord.gg" (growth spam)
  • "grow your channel", "easy money" (scams)
  • Multiple URLs (spam)
  • Common scam keywords

Actions: Warden flags suspicious messages (not auto-delete)

Database Schema

StreamSession

  • id (UUID) - Primary key
  • channel_name - Twitch channel
  • started_at - Session start time
  • ended_at - Session end time (null if active)
  • theme - Stream theme
  • is_active - Boolean flag

ChatMessage

  • id (UUID)
  • session_id - Reference to session
  • username - Message author
  • content - Message text
  • timestamp - Message time
  • is_bot, is_moderator - Flags

AgentAction

  • id (UUID)
  • session_id - Reference to session
  • action_type - RESPONSE, FLAG_SUSPICIOUS, ARCHIVE_CLIP, etc.
  • mode - Which agent mode took action
  • triggered_by_message_id - Message that triggered action
  • description - Action details

ClipCandidate

  • id (UUID)
  • session_id, message_id
  • reason - Why it's clip-worthy

BlogSeed

  • id (UUID)
  • session_id
  • topic, description
  • related_messages - JSON array

LLM Integration

The system includes a pluggable LLM client that currently:

  • Generates mock responses when no provider is configured
  • Prepares for OpenAI, Ollama, and LM Studio integration

Current Mock Behavior:

  • Returns deterministic responses based on keywords
  • Useful for testing without API costs

Implementing Real Providers:

See app/llm/client.py for TODO comments marking where to integrate:

  • _generate_openai() - OpenAI API calls
  • _generate_ollama() - Ollama local API
  • _generate_lm_studio() - LM Studio API

Current Limitations

This is scaffolding, not production code:

  • Twitch EventSub connection is a stub (see TODO comments)
  • Chat sending is not implemented
  • LLM providers are not integrated yet (mock mode works)
  • No real OAuth flow for Twitch
  • Database migrations are automatic (no versioning)
  • No rate limiting on endpoints
  • No authentication/authorization
  • Ledger export is basic markdown (no formatting options)

Next Implementation Steps

  1. Implement real Twitch integration:

    • Implement EventSub WebSocket connection in app/twitch/eventsub.py
    • Implement send chat message API in app/twitch/chat.py
    • Add OAuth token exchange flow
  2. Integrate real LLM provider:

    • Choose provider (e.g., Ollama for self-hosted)
    • Implement _generate_ollama() or _generate_openai()
    • Test with actual model
  3. Enhance agent modes:

    • Refine Hearthkeeper timing logic
    • Implement Steward mention detection
    • Expand Warden pattern library
    • Complete Librarian topic extraction

Phase 2: User Experience

  1. Add UI/Dashboard:

    • Stream monitoring view
    • Ledger generation UI
    • Settings panel
  2. Improve exports:

    • Configurable markdown templates
    • JSON export option
    • Email distribution
  3. Add persistence:

    • Session history
    • Settings storage per channel
    • Analytics dashboard

Phase 3: Production Readiness

  1. Testing:

    • Unit tests for policies
    • Integration tests for agent modes
    • E2E tests for full flows
  2. DevOps:

    • Database migrations (Alembic)
    • Logging aggregation
    • Monitoring/alerting
  3. Performance:

    • Rate limiting
    • Caching for repeated LLM calls
    • Message deduplication

Development

Local Setup (Without Docker)

# Create virtual environment
python3.12 -m venv venv
source venv/bin/activate

# Install dependencies
pip install -r requirements.txt

# Create .env file
cp .env.example .env

# Run migrations (auto-created on app startup)
# Start app
python -m uvicorn app.main:app --reload

Database Access

# Connect to running PostgreSQL
docker-compose exec sanctum-db psql -U sanctum -d sanctum

# View tables
\dt

# Query sessions
SELECT id, channel_name, started_at FROM stream_sessions;

Logging

The application uses Python's standard logging. Configure in app/main.py:

logging.basicConfig(level=logging.DEBUG)

Contributing

When adding features:

  • Maintain async/await patterns throughout
  • Add type hints to all functions
  • Include docstrings with purpose and TODO comments for future work
  • Keep modes independent but shareable

License

(Add your license here)

Support

For issues or questions:

  1. Check TODO comments in relevant files
  2. Review the architecture overview
  3. File an issue with reproduction steps