major-domo-v2/AGENTS.md
Cal Corum d6ec2a11ec Add AGENTS.md with coding guidelines for AI agents
Comprehensive guide covering:
- Build/lint/test commands including single test execution
- Code style: imports, formatting, types, naming, error handling
- Discord patterns: @logged_command, autocomplete, embed emojis
- Service layer abstraction rules
- Model patterns (from_api_data, required IDs)
- Testing with aioresponses and complete model data
- Critical rules for git, services, and commits

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 15:13:25 -06:00

5.8 KiB

AGENTS.md - Discord Bot v2.0

Guidelines for AI coding agents working in this repository.

Quick Reference

Start bot: python bot.py Run all tests: python -m pytest --tb=short -q Run single test file: python -m pytest tests/test_models.py -v Run single test: python -m pytest tests/test_models.py::TestTeamModel::test_team_creation_minimal -v Run tests matching pattern: python -m pytest -k "test_player" -v

Project Structure

  • bot.py - Main entry point
  • commands/ - Discord slash commands (package-based)
  • services/ - API service layer (BaseService pattern)
  • models/ - Pydantic data models
  • views/ - Discord UI components (embeds, modals)
  • utils/ - Logging, decorators, caching
  • tests/ - pytest test suite

Code Style

Imports

Order: stdlib, third-party, local. Separate groups with blank lines.

import asyncio
from typing import Optional, List

import discord
from discord.ext import commands

from services.player_service import player_service
from utils.decorators import logged_command

Formatting

  • Line length: 100 characters max
  • Docstrings: Google style with triple quotes
  • Indentation: 4 spaces
  • Trailing commas in multi-line structures

Type Hints

Always use type hints for function signatures:

async def get_player(self, player_id: int) -> Optional[Player]:
async def search_players(self, query: str, limit: int = 10) -> List[Player]:

Naming Conventions

  • Classes: PascalCase (PlayerService, TeamInfoCommands)
  • Functions/methods: snake_case (get_player, search_players)
  • Constants: UPPER_SNAKE_CASE (SBA_CURRENT_SEASON)
  • Private: prefix with _ (_client, _team_service)

Error Handling

Use custom exceptions from exceptions.py. Prefer "raise or return" over Optional:

from exceptions import APIException, PlayerNotFoundError

async def get_player(self, player_id: int) -> Player:
    result = await self.get_by_id(player_id)
    if result is None:
        raise PlayerNotFoundError(f"Player {player_id} not found")
    return result

Discord Command Patterns

Always use @logged_command decorator

Eliminates boilerplate logging. Class must have self.logger attribute:

class PlayerInfoCommands(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.logger = get_contextual_logger(f'{__name__}.PlayerInfoCommands')

    @discord.app_commands.command(name="player")
    @logged_command("/player")
    async def player_command(self, interaction, name: str):
        # Business logic only - no try/catch boilerplate needed
        player = await player_service.get_player_by_name(name)
        await interaction.followup.send(embed=create_embed(player))

Autocomplete: Use standalone functions (not methods)

async def player_name_autocomplete(
    interaction: discord.Interaction,
    current: str,
) -> List[discord.app_commands.Choice[str]]:
    if len(current) < 2:
        return []
    try:
        players = await player_service.search_players(current, limit=25)
        return [discord.app_commands.Choice(name=p.name, value=p.name) for p in players]
    except Exception:
        return []  # Never break autocomplete

class MyCommands(commands.Cog):
    @discord.app_commands.command()
    @discord.app_commands.autocomplete(name=player_name_autocomplete)
    async def my_command(self, interaction, name: str): ...

Embed emoji rules

Template methods auto-add emojis. Never double up:

# CORRECT - template adds emoji
embed = EmbedTemplate.success(title="Operation Completed")  # Results in: "Operation Completed"

# WRONG - double emoji
embed = EmbedTemplate.success(title="Operation Completed")  # Results in: " Operation Completed"

# For custom emoji, use create_base_embed
embed = EmbedTemplate.create_base_embed(title="Custom Title", color=EmbedColors.SUCCESS)

Service Layer

Never bypass services for API calls

# CORRECT
player = await player_service.get_player(player_id)

# WRONG - never do this
client = await player_service.get_client()
await client.get(f'players/{player_id}')

Key service methods

  • TeamService.get_team(team_id) - not get_team_by_id()
  • PlayerService.search_players(query, limit, all_seasons=True) - cross-season search

Models

Use from_api_data() classmethod

player = Player.from_api_data(api_response)

Database entities require id field

class Player(SBABaseModel):
    id: int = Field(..., description="Player ID from database")  # Required, not Optional

Testing

Use aioresponses for HTTP mocking

from aioresponses import aioresponses

@pytest.mark.asyncio
async def test_get_player():
    with aioresponses() as m:
        m.get("https://api.example.com/v3/players/1", payload={"id": 1, "name": "Test"})
        result = await api_client.get("players", object_id=1)
        assert result["name"] == "Test"

Provide complete model data

Pydantic validates all fields. Use helper functions for test data:

def create_player_data(player_id: int, name: str, **kwargs):
    return {"id": player_id, "name": name, "wara": 2.5, "season": 13, "pos_1": "CF", **kwargs}

Critical Rules

  1. Git: Never commit directly to main. Create feature branches.
  2. Services: Always use service layer methods, never direct API client access.
  3. Embeds: Don't add emojis to titles when using template methods (success/error/warning/info).
  4. Tests: Include docstrings explaining "what" and "why" for each test.
  5. Commits: Do not commit without user approval.

Documentation

Check CLAUDE.md files in directories for detailed patterns:

  • commands/CLAUDE.md - Command architecture
  • services/CLAUDE.md - Service patterns
  • models/CLAUDE.md - Model validation
  • tests/CLAUDE.md - Testing strategies