Welcome to the Tux Developer Guide! This comprehensive resource covers everything you need to contribute to Tux development.

Who Is This For?

This guide is for:

  • Contributors who want to add features or fix bugs
  • Developers learning the Tux codebase
  • Maintainers working on core systems
  • Anyone interested in how Tux works internally

If you're using or deploying Tux, see the User Guide or Admin Guide instead.

Quick Navigation

🚀 Getting Started

New to Tux development? Start here:

🏗️ Architecture

Understanding the system:

🔧 Core Systems

Deep dives into key systems:

📐 Patterns & Best Practices

Learn our coding patterns:

📚 How-To Guides

Step-by-step tutorials:

🧩 Module Deep Dives

Understanding key modules:

🗄️ Database

Working with data:

🧪 Testing

Ensure quality:

🛠️ CLI Tools

Development tools:

🎨 UI System

Building interfaces:

🤝 Contributing

Join the team:

Quick Start

1. Set Up Environment

# Clone repository
git clone https://github.com/allthingslinux/tux.git
cd tux

# Install UV and dependencies
curl -LsSf https://astral.sh/uv/install.sh | sh
uv sync

# Set up pre-commit hooks
uv run pre-commit install

Full Setup Guide →

2. Start Development

# Start database
uv run docker up

# Run migrations
uv run db push

# Start bot with hot-reload
uv run tux start --debug

3. Make Changes

  • Edit code in src/tux/
  • Bot automatically reloads on save
  • Test in Discord

4. Run Quality Checks

# Run all checks
uv run dev all

# Or individually
uv run dev lint
uv run dev format
uv run dev type-check
uv run tests run

5. Submit PR

# Create branch
git checkout -b feature/my-feature

# Commit with conventional commits
git commit -m "feat: add awesome feature"

# Push and create PR
git push origin feature/my-feature

First Contribution Guide →

Project Overview

Tech Stack

  • Language: Python 3.13+
  • Framework: discord.py 2.6+
  • Package Manager: UV
  • Database: PostgreSQL with SQLModel + SQLAlchemy
  • Migrations: Alembic
  • Logging: Loguru
  • Error Tracking: Sentry SDK
  • HTTP Client: httpx
  • CLI: Typer
  • Type Checking: Basedpyright (strict mode)
  • Linting/Formatting: Ruff
  • Testing: pytest with py-pglite
  • Documentation: MkDocs Material + mkdocstrings

Architecture Principles

  • Async-first: All I/O operations use async/await
  • Type safety: Strict type hints throughout
  • Dependency Injection: Controllers injected via BaseCog
  • Controller Pattern: Database access through controllers
  • Service Layer: External APIs wrapped in services
  • Plugin System: Extensible via plugins
  • Hot Reload: Fast development iteration
  • Comprehensive Testing: Unit, integration, and E2E tests

Codebase Structure

tux/
├── src/tux/              # Main source code
│   ├── core/             # Core bot functionality
│   │   ├── app.py        # Application lifecycle
│   │   ├── bot.py        # Bot class
│   │   ├── base_cog.py   # Base class for cogs
│   │   ├── permission_system.py
│   │   └── setup/        # Startup orchestration
│   ├── database/
│   │   ├── models/       # SQLModel models
│   │   ├── controllers/  # Database controllers
│   │   ├── migrations/   # Alembic migrations
│   │   └── service.py    # Database service
│   ├── modules/          # Command modules (cogs)
│   │   ├── moderation/   # Mod commands
│   │   ├── utility/      # Utility commands
│   │   ├── features/     # Feature modules
│   │   └── ...
│   ├── services/         # Service layer
│   │   ├── handlers/     # Event/error handlers
│   │   ├── hot_reload/   # Hot reload system
│   │   ├── moderation/   # Moderation coordinator
│   │   ├── sentry/       # Sentry integration
│   │   └── wrappers/     # API wrappers
│   ├── ui/               # UI components
│   │   ├── embeds.py     # Embed creator
│   │   ├── views/        # Discord views
│   │   ├── modals/       # Discord modals
│   │   └── buttons.py    # Buttons
│   ├── shared/           # Shared utilities
│   │   ├── config/       # Configuration system
│   │   ├── constants.py  # Constants
│   │   └── exceptions.py # Custom exceptions
│   ├── help/             # Custom help system
│   └── plugins/          # Plugin system
├── scripts/              # CLI tools
│   ├── cli.py            # Unified CLI
│   ├── db.py             # Database CLI
│   ├── dev.py            # Dev tools CLI
│   ├── tests.py          # Test runner CLI
│   └── ...
├── tests/                # Test suite
│   ├── unit/             # Unit tests
│   ├── integration/      # Integration tests
│   ├── e2e/              # End-to-end tests
│   └── fixtures/         # Test fixtures
├── docs/                 # Documentation
└── pyproject.toml        # Project configuration

Detailed Structure →

Development Workflow

Daily Development

# Start services
uv run docker up

# Start bot (with hot-reload)
uv run tux start --debug

# Make changes → bot reloads automatically

# Run checks before committing
uv run dev all
uv run tests run

Database Changes

# Modify models in src/tux/database/models/

# Generate migration
uv run db new "add user preferences"

# Review migration file in src/tux/database/migrations/versions/

# Apply migration
uv run db push

# Test changes

Adding a Command

  1. Create file in appropriate module directory
  2. Inherit from BaseCog
  3. Add @commands.hybrid_command decorator
  4. Implement command logic
  5. Add docstring (numpy format)
  6. Write tests
  7. Update documentation

Full Guide →

Testing

# Run all tests
uv run tests run

# Run specific category
uv run pytest -m unit
uv run pytest -m integration

# Run specific file
uv run pytest tests/unit/test_config_loaders.py

# Run with coverage report
uv run tests coverage

Testing Guide →

Code Style

Type Hints

All functions must have type hints:

def get_user_rank(user_id: int, guild_id: int) -> int | None:
    """Get user's permission rank."""
    ...

Docstrings

Use numpy-style docstrings:

def timeout_user(user: discord.Member, duration: int, reason: str) -> Case:
    """
    Timeout a user for a specified duration.

    Parameters
    ----------
    user : discord.Member
        The user to timeout.
    duration : int
        Timeout duration in seconds.
    reason : str
        Reason for the timeout.

    Returns
    -------
    Case
        The created moderation case.

    Raises
    ------
    discord.Forbidden
        Bot lacks permissions.
    ValueError
        Invalid duration.
    """
    ...

Async Patterns

Use async for I/O operations:

# ✅ Good
async def get_user_data(user_id: int) -> UserData:
    async with self.db.session() as session:
        result = await session.execute(...)
        return result.scalar_one()

# ❌ Bad - blocking call
def get_user_data(user_id: int) -> UserData:
    session = self.db.session()
    result = session.execute(...)
    return result.scalar_one()

Controller Pattern

Use controllers for database access:

# ✅ Good - via controller
class MyCog(BaseCog):
    def __init__(self, bot: Tux) -> None:
        super().__init__(bot)
        self.case_controller = self.db.case

    async def create_case(self, ...):
        case = await self.case_controller.insert_case(...)

# ❌ Bad - direct database access
class MyCog(BaseCog):
    async def create_case(self, ...):
        async with db.session() as session:
            case = Case(...)
            session.add(case)

Code Standards →

Key Concepts

Cogs (Modules)

Cogs are modular command groups:

class MyCog(BaseCog):
    """My command group."""

    def __init__(self, bot: Tux) -> None:
        super().__init__(bot)
        self.controller = self.db.my_controller

    @commands.hybrid_command()
    async def mycommand(self, ctx: commands.Context[Tux]) -> None:
        """Command description."""
        ...

Cog System →

Hybrid Commands

Commands work as both slash and prefix commands:

@commands.hybrid_command(name="ban", aliases=["b"])
@commands.guild_only()
@requires_command_permission()
async def ban(
    self,
    ctx: commands.Context[Tux],
    user: discord.Member,
    *,
    reason: str = "No reason provided",
) -> None:
    """Ban a user from the server."""
    ...

Command System →

Permission Ranks

Dynamic rank-based permissions (0-7):

@requires_command_permission()  # Uses default rank for command
async def moderate_command(self, ctx: commands.Context[Tux]) -> None:
    """Moderation command."""
    ...

Permission System →

Tools & Commands

Development Commands

# Bot management
uv run tux start           # Start bot
uv run tux start --debug   # Debug mode
uv run tux version         # Version info

# Code quality
uv run dev lint            # Lint with Ruff
uv run dev format          # Format with Ruff
uv run dev type-check      # Type check with Basedpyright
uv run dev lint-docstring  # Lint docstrings
uv run dev all             # All checks

# Database
uv run db push             # Apply migrations
uv run db new "message"    # Create migration
uv run db status           # Migration status
uv run db health           # Health check
uv run db tables           # List tables

# Testing
uv run tests run           # All tests with coverage
uv run tests quick         # Quick run without coverage
uv run tests coverage      # Coverage report

# Docker
uv run docker up           # Start services
uv run docker down         # Stop services
uv run docker logs         # View logs

# Documentation
uv run docs serve          # Serve docs locally
uv run docs build          # Build static docs

CLI Reference →

Getting Help

Documentation

Community

Resources

What's Next?

New Contributors

  1. Development Setup - Get environment ready
  2. Project Structure - Learn the layout
  3. First Contribution - Make your first PR

Understanding the System

  1. Architecture Overview - High-level design
  2. Bot Lifecycle - How Tux starts
  3. Core Systems - Key subsystems

Building Features

  1. Creating a Cog - Add command module
  2. Database Operations - Work with data
  3. UI Components - Build interfaces

Ready to contribute? Start with Development Setup!