diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..1b3646f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,248 @@ +# AGENTS.md + +Guidelines for AI coding assistants working on the am_bot codebase. + +## Project Overview + +am_bot is a Discord bot for the ARK Modding community, built with discord.py 2.x. It uses a cog-based architecture where each feature is isolated in its own module under `am_bot/cogs/`. + +## Architecture + +### Core Components + +- **`am_bot/bot.py`** — Main `ARKBot` class extending `discord.ext.commands.Bot`. Handles initialization, intents, and cog loading. +- **`am_bot/cogs/`** — Feature modules (cogs) that encapsulate related functionality. +- **`am_bot/constants.py`** — Server-specific IDs (guild, channels, roles). These are hardcoded for the ARK Modding Discord. +- **`am_bot/ses.py`** — AWS SES email utility used by `invite_response.py`. + +### Cog Pattern + +Each cog follows this pattern: + +```python +import discord +from discord.ext import commands + +class MyCog(commands.Cog): + def __init__(self, bot: discord.ext.commands.Bot): + self.bot = bot + + def cog_load(self) -> None: + # Called when cog is loaded — start background tasks here + self.bot.loop.create_task(self.my_task()) + + def cog_unload(self) -> None: + # Cleanup when cog is unloaded + pass + + @commands.Cog.listener() + async def on_message(self, message: discord.Message): + # Event listeners + pass + + @commands.command() + async def mycommand(self, ctx): + """Command docstring shows in help""" + pass +``` + +### Adding New Cogs + +1. Create the cog file in `am_bot/cogs/` +2. Import and register in `am_bot/bot.py`: + ```python + from .cogs.my_cog import MyCog + # ... in add_cogs(): + await self.add_cog(MyCog(self)) + ``` +3. Add corresponding test file in `tests/test_my_cog.py` + +## Code Style + +### Formatting + +- **Line length**: 79 characters +- **Formatter**: black +- **Import sorting**: isort (black profile) +- **Linter**: ruff + +Run `tox -e lint` to verify or use pre-commit hooks. + +### Conventions + +- Use `discord.ext.commands.Bot` type hints for bot parameters +- Prefer `AsyncMock` for async method mocks in tests +- Use `MagicMock` for synchronous Discord objects +- Log using `logging.getLogger(__name__)` +- Background tasks should use `self.bot.loop.create_task()` in `cog_load()` + +## Testing + +### Test Structure + +Tests are in `tests/` with one file per cog: +- `test_bot.py` — Core bot tests +- `test_greetings.py` — GreetingsCog tests +- `test_quarantine.py` — QuarantineCog tests +- etc. + +### Test Fixtures + +`tests/conftest.py` provides mock factories for Discord objects: + +```python +# Available fixture factories: +make_mock_bot() +make_mock_guild() +make_mock_channel() +make_mock_member() +make_mock_message() +make_mock_embed() +make_mock_role() +make_mock_reaction_payload() +make_mock_voice_state() + +# Available pytest fixtures: +@pytest.fixture def mock_bot() +@pytest.fixture def mock_guild() +@pytest.fixture def mock_channel() +@pytest.fixture def mock_member() +@pytest.fixture def mock_message() +``` + +### Writing Tests + +```python +import pytest +from am_bot.cogs.my_cog import MyCog +from conftest import make_mock_bot, make_mock_message + +@pytest.mark.asyncio +async def test_my_feature(): + bot = make_mock_bot() + cog = MyCog(bot) + message = make_mock_message(content="test") + + await cog.on_message(message) + + message.channel.send.assert_called_once() +``` + +### Coverage Requirements + +- Minimum 90% coverage enforced via `tox -e unittest` +- All new code should have corresponding tests +- Use `coverage run -m pytest tests/ && coverage report` to check + +## Running Tests + +```bash +# Full test suite (lint + tests on Python 3.10-3.13) +tox + +# Just unit tests +tox -e unittest + +# Just linting +tox -e lint + +# Quick pytest run +pytest tests/ -v + +# With coverage +coverage run -m pytest tests/ && coverage report +``` + +## Dependencies + +### Runtime (requirements.txt) +- `discord.py==2.3.2` — Discord API wrapper +- `boto3==1.33.7` — AWS SDK (for SES email) +- `audioop-lts==0.2.1` — Audio support for voice features + +### Development (pyproject.toml [dev]) +- `pytest`, `pytest-asyncio`, `pytest-cov` — Testing +- `black`, `isort`, `ruff`, `bandit` — Code quality +- `pre-commit` — Git hooks +- `tox` — Test automation + +## Common Tasks + +### Add a new command response + +Edit `am_bot/cogs/command_responses.json`: + +```json +{ + "!": { + "mycommand": { + "content": "Response text here" + } + } +} +``` + +### Add a new reaction role + +Edit `am_bot/cogs/assignable_roles.json`: + +```json +{ + "🎮": { + "name": "Gamer", + "role_id": 123456789, + "channel_id": 987654321, + "message_id": 111222333 + } +} +``` + +### Add environment-based configuration + +1. Read in the cog with `os.getenv()`: + ```python + MY_SETTING = int(os.getenv("MY_SETTING", 0)) + ``` +2. Document in README.md environment variables table +3. Add to Helm values if needed + +## Deployment + +### Docker + +```bash +docker build -t am_bot . +docker run -d --env-file .env am_bot +``` + +### Kubernetes/Helm + +The Helm chart is in `helm/am-bot/`. Override values in your deployment: + +```yaml +# values.yaml +image: + repository: your-registry/am_bot + tag: latest +env: + BOT_TOKEN: "your-token" +``` + +## Gotchas + +1. **Bot intents**: The bot requires `members` and `message_content` intents. Enable in Discord Developer Portal. + +2. **Constants are hardcoded**: `constants.py` has ARK Modding-specific IDs. For a different server, these must be changed. + +3. **Async in cogs**: All Discord event handlers and commands are async. Use `await` properly and `AsyncMock` in tests. + +4. **Reaction role reset**: `RoleAssignmentCog` clears and re-adds reactions every 10 minutes. This is intentional. + +5. **Workshop cleanup**: `WorkshopCog` purges messages older than 24 hours from the workshop text channel. + +6. **Starboard tracking**: `StarboardCog` loads existing starred message IDs on startup to prevent duplicates. + +## Questions? + +Check the existing cogs for patterns. The codebase is well-tested — reference `tests/conftest.py` for mock utilities. + diff --git a/README.md b/README.md index d6312fb..6c4f506 100644 --- a/README.md +++ b/README.md @@ -1,43 +1,191 @@ # am_bot -ARK Modding Discord Bot -## Setup -1. Install Python 3.11 or higher -2. Install requirements.txt +A feature-rich Discord bot built for the ARK Modding community. Built with [discord.py](https://discordpy.readthedocs.io/) and deployable to Kubernetes via Helm. - `pip install -r requirements.txt` -3. Create a .env file in the root directory +## Features - `echo "BOT_TOKEN=" > .env` -4. Run the bot +### Member Management +- **Greetings** — Automatically welcomes new members in the system channel +- **Quarantine** — Spam protection with honeypot channels and cross-channel duplicate detection +- **Role Assignment** — Reaction-based role self-assignment with automatic reaction reset - `python run.py` +### Community Features +- **Starboard** — Messages with 5+ ⭐ reactions get featured in a starboard channel +- **Server Stats** — Live member, boost, modder, and mapper counts displayed in channel names +- **Workshop** — Voice channel-linked text channel with automatic access management and cleanup + +### Communication +- **Responses** — Configurable command responses defined in JSON +- **Invite Response** — Staff can respond to invite help requests via email (AWS SES) + +## Requirements + +- Python 3.10 or higher +- Discord Bot Token +- AWS credentials (for email functionality via SES) + +## Quick Start + +### Local Development + +```bash +# Clone the repository +git clone https://github.com/ARKModding/am_bot.git +cd am_bot + +# Create and activate virtual environment +python -m venv venv +source venv/bin/activate # Linux/macOS +# or +venv\Scripts\activate # Windows + +# Install dependencies +pip install -r requirements.txt + +# Configure environment +echo "BOT_TOKEN=your_bot_token_here" > .env + +# Run the bot +python run.py +``` ### Docker -1. Install Docker -2. Build the image - `docker build -t am_bot .` -3. Setup `.env` file (copy `.env_SAMPLE` to `.env` and fill in the values) -4. Run the image +```bash +# Build the image +docker build -t am_bot . + +# Create .env file with your configuration +cp .env_SAMPLE .env +# Edit .env with your values + +# Run the container +docker run -d --rm --name am_bot --env-file .env am_bot +``` + +### Kubernetes (Helm) + +```bash +# Install via Helm +helm upgrade --install am-bot ./helm/am-bot -f values.yaml +``` + +## Configuration + +### Environment Variables + +| Variable | Description | Required | +|----------|-------------|----------| +| `BOT_TOKEN` | Discord bot authentication token | Yes | +| `AWS_ACCESS_KEY_ID` | AWS access key for SES | For email | +| `AWS_SECRET_ACCESS_KEY` | AWS secret key for SES | For email | +| `QUARANTINE_HONEYPOT_CHANNEL_ID` | Channel ID for honeypot quarantine | No | +| `QUARANTINE_ROLE_ID` | Role ID to assign to quarantined users | No | +| `SPAM_SIMILARITY_THRESHOLD` | Similarity ratio for spam detection (0.0-1.0, default: 0.85) | No | +| `SPAM_CHANNEL_THRESHOLD` | Number of channels for spam trigger (default: 3) | No | +| `MESSAGE_HISTORY_SECONDS` | Message history retention in seconds (default: 3600) | No | +| `SPAM_MIN_MESSAGE_LENGTH` | Minimum message length for spam detection (default: 20) | No | + +### Configuration Files - `docker run -d --rm --name am_bot --env-file .env am_bot` +- `am_bot/cogs/command_responses.json` — Custom command trigger/response mappings +- `am_bot/cogs/assignable_roles.json` — Reaction role configuration +- `am_bot/constants.py` — Server-specific channel and role IDs +## Development + +### Setup + +```bash +# Install development dependencies +pip install -e '.[dev]' + +# Install pre-commit hooks +pre-commit install +``` + +### Testing + +```bash +# Run all tests with tox +tox + +# Run only unit tests +tox -e unittest + +# Run only linting +tox -e lint + +# Run tests directly with pytest +pytest tests/ -v + +# Run with coverage +coverage run -m pytest tests/ +coverage report +``` + +### Code Quality + +The project uses the following tools: +- **black** — Code formatting (line length: 79) +- **isort** — Import sorting +- **ruff** — Fast linting +- **bandit** — Security analysis + +All checks are run via pre-commit hooks and in CI. + +## Project Structure + +``` +am_bot/ +├── am_bot/ +│ ├── __init__.py # Package init, version +│ ├── bot.py # Main ARKBot class +│ ├── constants.py # Server-specific IDs +│ ├── ses.py # AWS SES email utility +│ └── cogs/ +│ ├── greetings.py # Welcome messages, hello command +│ ├── invite_response.py # Email responses to invite requests +│ ├── quarantine.py # Spam detection and honeypot +│ ├── responses.py # Custom command responses +│ ├── role_assignment.py # Reaction-based role assignment +│ ├── server_stats.py # Live stat channel updates +│ ├── starboard.py # Star reaction feature board +│ ├── workshop.py # Workshop voice/text channel management +│ ├── command_responses.json +│ └── assignable_roles.json +├── tests/ # Test suite (90%+ coverage required) +├── helm/am-bot/ # Kubernetes Helm chart +├── pyproject.toml # Project configuration +├── requirements.txt # Runtime dependencies +├── tox.ini # Test automation +├── Dockerfile # Container build +└── run.py # Application entrypoint +``` ## Contributing + 1. Fork the repository 2. Clone your fork -3. Create a virtual environment - - `python -m venv venv` -4. Install development requirements +3. Create a virtual environment and install dev dependencies: + ```bash + python -m venv venv + source venv/bin/activate + pip install -e '.[dev]' + ``` +4. Install pre-commit hooks: + ```bash + pre-commit install + ``` +5. Create a feature branch +6. Make your changes +7. Test with your own bot token in a test server +8. Ensure tests pass and coverage remains ≥90%: + ```bash + tox + ``` +9. Create a pull request - `pip install -e '.[dev]'` -5. Install pre-commit hooks +## License - `pre-commit install` -6. Create a new branch -7. Make your changes -8. Test your changes with your own Bot Token (see Discord Bot Setup Docs) in your own server -9. Create a pull request -10. Wait for it to be reviewed and merged +This project is maintained by the ARK Modding community.