* Add 640x640 Intel NPU stats * use css instead of js for reviewed button hover state in filmstrip * update copilot instructions to copy HA's format * Set json schema for genai --------- Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
10 KiB
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 unittestto run tests - Language: American English for all code, comments, and documentation
Logging Standards
-
Logger Pattern: Use module-level logger
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 informationinfo: Important runtime events (startup, shutdown, state changes)warning: Recoverable issues that should be addressederror: Errors that affect functionality but don't crash the appexception: 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:
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:
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()nottime.sleep() - Avoid awaiting in loops - use
asyncio.gather()instead - No blocking calls in async functions
- Use
asyncio.create_task()for background operations
- Avoid sleeping in loops - use
- Thread Safety: Use proper synchronization for shared state
Documentation Standards
-
Module Docstrings: Concise descriptions at top of files
"""Utilities for motion detection and analysis.""" -
Function Docstrings: Required for public functions and methods
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()functionimport { useTranslation } from "react-i18next"; function MyComponent() { const { t } = useTranslation(["views/live"]); return <div>{t("camera_not_found")}</div>; } -
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: errorreact-hooks/exhaustive-deps: errorno-console: error (use proper logging or remove)@typescript-eslint/no-explicit-any: warn (always use proper types instead ofany)- 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
TestCaseclasses with descriptive test method namesclass 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
# 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)
# 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.
# Build local image
make local
# Build debug image
make debug
Common Patterns
API Endpoint Pattern
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
# Access Frigate configuration
config: FrigateConfig = request.app.frigate_config
camera_config = config.cameras["front_door"]
Database Queries
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
# Blocking operations in async functions
data = requests.get(url) # ❌ Use async HTTP client
time.sleep(5) # ❌ Use asyncio.sleep()
# Hardcoded strings in React components
<div>Camera not found</div> # ❌ 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
# 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();
<div>{t("camera_not_found")}</div> # ✅ 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