# GitHub Copilot Instructions for Frigate NVR This document provides coding guidelines and best practices for contributing to Frigate NVR, a complete and local NVR designed for Home Assistant with AI object detection. ## Project Overview Frigate NVR is a realtime object detection system for IP cameras that uses: - **Backend**: Python 3.13+ with FastAPI, OpenCV, TensorFlow/ONNX - **Frontend**: React with TypeScript, Vite, TailwindCSS - **Architecture**: Multiprocessing design with ZMQ and MQTT communication - **Focus**: Minimal resource usage with maximum performance ## Code Review Guidelines When reviewing code, do NOT comment on: - Missing imports - Static analysis tooling catches these - Code formatting - Ruff (Python) and Prettier (TypeScript/React) handle formatting - Minor style inconsistencies already enforced by linters ## Python Backend Standards ### Python Requirements - **Compatibility**: Python 3.13+ - **Language Features**: Use modern Python features: - Pattern matching - Type hints (comprehensive typing preferred) - f-strings (preferred over `%` or `.format()`) - Dataclasses - Async/await patterns ### Code Quality Standards - **Formatting**: Ruff (configured in `pyproject.toml`) - **Linting**: Ruff with rules defined in project config - **Type Checking**: Use type hints consistently - **Testing**: unittest framework - use `python3 -u -m unittest` to run tests - **Language**: American English for all code, comments, and documentation ### Logging Standards - **Logger Pattern**: Use module-level logger ```python import logging logger = logging.getLogger(__name__) ``` - **Format Guidelines**: - No periods at end of log messages - No sensitive data (keys, tokens, passwords) - Use lazy logging: `logger.debug("Message with %s", variable)` - **Log Levels**: - `debug`: Development and troubleshooting information - `info`: Important runtime events (startup, shutdown, state changes) - `warning`: Recoverable issues that should be addressed - `error`: Errors that affect functionality but don't crash the app - `exception`: Use in except blocks to include traceback ### Error Handling - **Exception Types**: Choose most specific exception available - **Try/Catch Best Practices**: - Only wrap code that can throw exceptions - Keep try blocks minimal - process data after the try/except - Avoid bare exceptions except in background tasks Bad pattern: ```python try: data = await device.get_data() # Can throw # ❌ Don't process data inside try block processed = data.get("value", 0) * 100 result = processed except DeviceError: logger.error("Failed to get data") ``` Good pattern: ```python try: data = await device.get_data() # Can throw except DeviceError: logger.error("Failed to get data") return # ✅ Process data outside try block processed = data.get("value", 0) * 100 result = processed ``` ### Async Programming - **External I/O**: All external I/O operations must be async - **Best Practices**: - Avoid sleeping in loops - use `asyncio.sleep()` not `time.sleep()` - Avoid awaiting in loops - use `asyncio.gather()` instead - No blocking calls in async functions - Use `asyncio.create_task()` for background operations - **Thread Safety**: Use proper synchronization for shared state ### Documentation Standards - **Module Docstrings**: Concise descriptions at top of files ```python """Utilities for motion detection and analysis.""" ``` - **Function Docstrings**: Required for public functions and methods ```python async def process_frame(frame: ndarray, config: Config) -> Detection: """Process a video frame for object detection. Args: frame: The video frame as numpy array config: Detection configuration Returns: Detection results with bounding boxes """ ``` - **Comment Style**: - Explain the "why" not just the "what" - Keep lines under 88 characters when possible - Use clear, descriptive comments ### File Organization - **API Endpoints**: `frigate/api/` - FastAPI route handlers - **Configuration**: `frigate/config/` - Configuration parsing and validation - **Detectors**: `frigate/detectors/` - Object detection backends - **Events**: `frigate/events/` - Event management and storage - **Utilities**: `frigate/util/` - Shared utility functions ## Frontend (React/TypeScript) Standards ### Internationalization (i18n) - **CRITICAL**: Never write user-facing strings directly in components - **Always use react-i18next**: Import and use the `t()` function ```tsx import { useTranslation } from "react-i18next"; function MyComponent() { const { t } = useTranslation(["views/live"]); return
{t("camera_not_found")}
; } ``` - **Translation Files**: Add English strings to the appropriate json files in `web/public/locales/en` - **Namespaces**: Organize translations by feature/view (e.g., `views/live`, `common`, `views/system`) ### Code Quality - **Linting**: ESLint (see `web/.eslintrc.cjs`) - **Formatting**: Prettier with Tailwind CSS plugin - **Type Safety**: TypeScript strict mode enabled - **Testing**: Vitest for unit tests ### Component Patterns - **UI Components**: Use Radix UI primitives (in `web/src/components/ui/`) - **Styling**: TailwindCSS with `cn()` utility for class merging - **State Management**: React hooks (useState, useEffect, useCallback, useMemo) - **Data Fetching**: Custom hooks with proper loading and error states ### ESLint Rules Key rules enforced: - `react-hooks/rules-of-hooks`: error - `react-hooks/exhaustive-deps`: error - `no-console`: error (use proper logging or remove) - `@typescript-eslint/no-explicit-any`: warn (always use proper types instead of `any`) - Unused variables must be prefixed with `_` - Comma dangles required for multiline objects/arrays ### File Organization - **Pages**: `web/src/pages/` - Route components - **Views**: `web/src/views/` - Complex view components - **Components**: `web/src/components/` - Reusable components - **Hooks**: `web/src/hooks/` - Custom React hooks - **API**: `web/src/api/` - API client functions - **Types**: `web/src/types/` - TypeScript type definitions ## Testing Requirements ### Backend Testing - **Framework**: Python unittest - **Run Command**: `python3 -u -m unittest` - **Location**: `frigate/test/` - **Coverage**: Aim for comprehensive test coverage of core functionality - **Pattern**: Use `TestCase` classes with descriptive test method names ```python class TestMotionDetection(unittest.TestCase): def test_detects_motion_above_threshold(self): # Test implementation ``` ### Test Best Practices - Always have a way to test your work and confirm your changes - Write tests for bug fixes to prevent regressions - Test edge cases and error conditions - Mock external dependencies (cameras, APIs, hardware) - Use fixtures for test data ## Development Commands ### Python Backend ```bash # Run all tests python3 -u -m unittest # Run specific test file python3 -u -m unittest frigate.test.test_ffmpeg_presets # Check formatting (Ruff) ruff format --check frigate/ # Apply formatting ruff format frigate/ # Run linter ruff check frigate/ ``` ### Frontend (from web/ directory) ```bash # Start dev server (AI agents should never run this directly unless asked) npm run dev # Build for production npm run build # Run linter npm run lint # Fix linting issues npm run lint:fix # Format code npm run prettier:write ``` ### Docker Development AI agents should never run these commands directly unless instructed. ```bash # Build local image make local # Build debug image make debug ``` ## Common Patterns ### API Endpoint Pattern ```python from fastapi import APIRouter, Request from frigate.api.defs.tags import Tags router = APIRouter(tags=[Tags.Events]) @router.get("/events") async def get_events(request: Request, limit: int = 100): """Retrieve events from the database.""" # Implementation ``` ### Configuration Access ```python # Access Frigate configuration config: FrigateConfig = request.app.frigate_config camera_config = config.cameras["front_door"] ``` ### Database Queries ```python from frigate.models import Event # Use Peewee ORM for database access events = ( Event.select() .where(Event.camera == camera_name) .order_by(Event.start_time.desc()) .limit(limit) ) ``` ## Common Anti-Patterns to Avoid ### ❌ Avoid These ```python # Blocking operations in async functions data = requests.get(url) # ❌ Use async HTTP client time.sleep(5) # ❌ Use asyncio.sleep() # Hardcoded strings in React components
Camera not found
# ❌ Use t("camera_not_found") # Missing error handling data = await api.get_data() # ❌ No exception handling # Bare exceptions in regular code try: value = await sensor.read() except Exception: # ❌ Too broad logger.error("Failed") ``` ### ✅ Use These Instead ```python # Async operations import aiohttp async with aiohttp.ClientSession() as session: async with session.get(url) as response: data = await response.json() await asyncio.sleep(5) # ✅ Non-blocking # Translatable strings in React const { t } = useTranslation();
{t("camera_not_found")}
# ✅ Translatable # Proper error handling try: data = await api.get_data() except ApiException as err: logger.error("API error: %s", err) raise # Specific exceptions try: value = await sensor.read() except SensorException as err: # ✅ Specific logger.exception("Failed to read sensor") ``` ## Project-Specific Conventions ### Configuration Files - Main config: `config/config.yml` ### Directory Structure - Backend code: `frigate/` - Frontend code: `web/` - Docker files: `docker/` - Documentation: `docs/` - Database migrations: `migrations/` ### Code Style Conformance Always conform new and refactored code to the existing coding style in the project: - Follow established patterns in similar files - Match indentation and formatting of surrounding code - Use consistent naming conventions (snake_case for Python, camelCase for TypeScript) - Maintain the same level of verbosity in comments and docstrings ## Additional Resources - Documentation: https://docs.frigate.video - Main Repository: https://github.com/blakeblackshear/frigate - Home Assistant Integration: https://github.com/blakeblackshear/frigate-hass-integration