# AGENTS.md - AI Coding Agent Guidelines This document provides guidelines for AI coding agents working in the labhelper repository. ## Project Overview - **Type**: Django web application - **Python**: 3.13.7 - **Django**: 5.2.9 - **Database**: SQLite (development) - **Virtual Environment**: `.venv/` ## Build/Run Commands ### Development Server ```bash python manage.py runserver # Start dev server on port 8000 python manage.py runserver 0.0.0.0:8000 # Bind to all interfaces ``` ### Database Operations ```bash python manage.py makemigrations # Create migration files python manage.py makemigrations boxes # Create migrations for specific app python manage.py migrate # Apply all migrations python manage.py showmigrations # List migration status ``` ### Testing ```bash # Run all tests python manage.py test # Run tests for a specific app python manage.py test boxes # Run a specific test class python manage.py test boxes.tests.TestClassName # Run a single test method python manage.py test boxes.tests.TestClassName.test_method_name # Run tests with verbosity python manage.py test -v 2 # Run tests with coverage coverage run manage.py test coverage report coverage html # Generate HTML report ``` ### Django Shell ```bash python manage.py shell # Interactive Django shell python manage.py createsuperuser # Create admin user python manage.py collectstatic # Collect static files ``` ### Production ```bash gunicorn labhelper.wsgi:application # Run with Gunicorn ``` ## Code Style Guidelines ### Python Style - Follow PEP 8 conventions - Use 4-space indentation (no tabs) - Maximum line length: 79 characters (PEP 8 standard) - Use single quotes for strings: `'string'` - Use double quotes for docstrings: `"""Docstring."""` ### Import Order Organize imports in this order, with blank lines between groups: ```python # 1. Standard library imports import os import sys from pathlib import Path # 2. Django imports from django.db import models from django.contrib import admin from django.shortcuts import render, redirect from django.http import HttpResponse, JsonResponse # 3. Third-party imports import requests from markdown import markdown # 4. Local application imports from .models import MyModel from .forms import MyForm ``` ### Naming Conventions | Type | Convention | Example | |------|------------|---------| | Modules | lowercase_with_underscores | `user_profile.py` | | Classes | PascalCase | `UserProfile` | | Functions | lowercase_with_underscores | `get_user_data()` | | Constants | UPPERCASE_WITH_UNDERSCORES | `MAX_CONNECTIONS` | | Variables | lowercase_with_underscores | `user_count` | | Django Models | PascalCase (singular) | `Box`, `UserProfile` | | Django Apps | lowercase (short) | `boxes`, `users` | ### Django-Specific Conventions **Models:** ```python from django.db import models class Box(models.Model): """A storage box in the lab.""" name = models.CharField(max_length=255) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: verbose_name_plural = 'boxes' ordering = ['-created_at'] def __str__(self): return self.name ``` **Views:** ```python from django.shortcuts import render, get_object_or_404 from django.http import Http404 def box_detail(request, box_id): """Display details for a specific box.""" box = get_object_or_404(Box, pk=box_id) return render(request, 'boxes/detail.html', {'box': box}) ``` ### Error Handling ```python # Use specific exceptions try: result = some_operation() except SpecificError as exc: raise CustomError('Descriptive message') from exc # Django: Use get_object_or_404 for model lookups box = get_object_or_404(Box, pk=box_id) # Log errors appropriately import logging logger = logging.getLogger(__name__) logger.error('Error message: %s', error_detail) ``` ### Type Hints (Recommended) ```python from typing import Optional from django.http import HttpRequest, HttpResponse def get_box(request: HttpRequest, box_id: int) -> HttpResponse: """Retrieve a box by ID.""" ... ``` ## Project Structure ``` labhelper/ ├── manage.py # Django CLI entry point ├── requirements.txt # Python dependencies ├── labhelper/ # Project configuration │ ├── settings.py # Django settings │ ├── urls.py # Root URL routing │ ├── wsgi.py # WSGI application │ └── asgi.py # ASGI application └── boxes/ # Django app ├── admin.py # Admin configuration ├── apps.py # App configuration ├── models.py # Data models ├── views.py # View functions ├── tests.py # Test cases ├── migrations/ # Database migrations └── templates/ # HTML templates ``` ## Available Django Extensions The project includes these pre-installed packages: - **django-mptt**: Tree structures (categories, hierarchies) - **django-mptt-admin**: Admin interface for MPTT models - **django-admin-sortable2**: Drag-and-drop ordering in admin - **django-nested-admin**: Nested inline forms in admin - **django-nested-inline**: Additional nested inline support - **django-revproxy**: Reverse proxy functionality ## Testing Guidelines - Use `django.test.TestCase` for database tests - Use `django.test.SimpleTestCase` for tests without database - Name test files `test_*.py` or `*_tests.py` - Name test methods `test_*` - Use descriptive test method names ```python from django.test import TestCase from .models import Box class BoxModelTests(TestCase): """Tests for the Box model.""" def setUp(self): """Set up test fixtures.""" self.box = Box.objects.create(name='Test Box') def test_box_str_returns_name(self): """Box __str__ should return the box name.""" self.assertEqual(str(self.box), 'Test Box') ``` ## Files to Never Commit Per `.gitignore`: - `__pycache__/`, `*.pyc` - Python bytecode - `.venv/` - Virtual environment - `.env` - Environment variables - `data/db.sqlite3` - Database file - `keys/` - Secret keys ## Common Pitfalls 1. **Always activate venv**: `source .venv/bin/activate` 2. **Run migrations after model changes**: `makemigrations` then `migrate` 3. **Add new apps to INSTALLED_APPS** in `settings.py` 4. **Use get_object_or_404** instead of bare `.get()` calls 5. **Never commit SECRET_KEY** - use environment variables in production ## Deployment Commands ### Prepare a Full Deployment When instructed to "Prepare a full deployment", perform the following steps: 1. **Bump container versions**: In `argocd/deployment.yaml`, increment the version numbers by 0.001 for both containers: - `labhelper-data-loader` (initContainer) - `labhelper` (main container) 2. **Copy database**: Copy the current development database to the data-loader preload location: ```bash cp data/db.sqlite3 data-loader/preload.sqlite3 ``` ### Prepare a Partial Deployment When instructed to "Prepare a partial deployment", perform the following step: 1. **Bump main container version only**: In `argocd/deployment.yaml`, increment the version number by 0.001 for the main container only: - `labhelper` (main container) Do NOT bump the data-loader version or copy the database.