Guidelines for AI agents working on the ForgeSyte Plugins repository.
This repository contains independent pip-installable plugins for the ForgeSyte platform. Each plugin is located in plugins/<plugin-name> and follows a standardized structure.
forgesyte-plugins/
├── plugins/
│ ├── forgesyte-yolo-tracker/ # YOLO sports analysis plugin
│ ├── ocr/
│ ├── block_mapper/
│ ├── moderation/
│ ├── motion_detector/
│ └── plugin_template/ # Template for new plugins
├── scripts/ # Utility scripts
├── docs/ # Documentation
└── README.md # Main readme
cd plugins/<plugin-name>
# Create virtual environment
uv venv --python 3.9
source .venv/bin/activate
# Install plugin in development mode
uv pip install -e .
# Install with all dependencies
uv pip install -e ".[dev]"From plugin directory (plugins/forgesyte-yolo-tracker/):
Contract tests only (fast, CI-safe):
make test-fast
# or: pytest tests_contract -v --cov --cov-report=term-missingHeavy tests only (requires GPU/models):
make test-heavy
# or: pytest tests_heavy -v -m heavyAll tests (contract + heavy):
make test-all
# or: pytest tests_contract tests_heavy -vQuality checks:
make lint # ruff check + fix
make format # black + isort
make type-check # mypy# Linting
uv run ruff check src/ --fix
# Type checking
uv run mypy src/
# Formatting
uv run black src/
uv run isort src/Always run these before committing:
# Lint and format
uv run ruff check src/ --fix
# Type check
uv run mypy src/
# Run tests
uv run pytest src/tests/ -vAlways create a new branch for changes:
# Create and switch to new branch
git checkout -b feature/my-new-feature
# Or for bug fixes
git checkout -b fix/description-of-fix
# Or for refactoring
git checkout -b refactor/component-being-refactored# Stage changes
git add .
# Commit with proper message format
git commit -m "feat(yolo-tracker): Add player detection inference
Implement detect_players_json() and detect_players_json_with_annotated_frame()
Closes #32"# Push branch to remote
git push -u origin feature/my-new-feature# Create PR using gh CLI
gh pr create --title "feat(yolo-tracker): Add player detection" \
--body "## Summary
Add player detection inference module.
## Changes
- Add inference/player_detection.py
- Add tests for detect_players_json
- Update manifest.json
## Testing
- All tests pass
- Ruff lint clean
- Mypy type check clean
Closes #32" \
--label enhancement- Wait for review/approval
- Merge PR via GitHub UI or CLI:
gh pr merge --admin --merge
- Delete branch after merge:
git checkout main && git pull && git branch -d feature/my-new-feature
| Type | Prefix | Example |
|---|---|---|
| Feature | feature/ |
feature/radar-visualization |
| Bug Fix | fix/ |
fix/memory-leak-detection |
| Refactor | refactor/ |
refactor/plugin-initialization |
| Docs | docs/ |
docs/update-readme |
| Experiment | experiment/ |
experiment/new-tracking-algorithm |
<type>(<scope>): <subject>
- feat(yolo-tracker): Add radar visualization
- fix(ocr): Fix text extraction bug
- refactor(moderation): Simplify rule engine
- docs(readme): Add installation instructions
ALWAYS create a branch for:
- New features
- Bug fixes
- Refactoring changes
- Documentation updates
- Test additions
Direct commits to main are NOT allowed.
## Summary
Brief description of changes.
## Changes
- List of files changed
- What was modified in each file
## Testing
- Test results
- Any manual testing done
## Checklist
- [ ] Tests pass
- [ ] Ruff lint clean
- [ ] Mypy type check clean
- [ ] Documentation updated (if applicable)
## Related Issue
Closes #XXAll tests follow this pattern:
- Fast tests: No model loading, mock dependencies, run on CPU
- Model tests: Require YOLO model loading, skipped by default
- Integration tests: Require GPU, skipped by default
Each test file with model dependencies MUST include:
import os
import pytest
RUN_MODEL_TESTS = os.getenv("RUN_MODEL_TESTS", "0") == "1"
pytestmark = pytest.mark.skipif(
not RUN_MODEL_TESTS,
reason="Set RUN_MODEL_TESTS=1 to run (requires YOLO model)"
)When adding a new inference module:
Step 1: Write failing tests first
# Create test file
touch src/tests/test_inference_new_feature.py
# Write tests with proper skip markers
# Run to verify they fail (module doesn't exist yet)
uv run pytest src/tests/test_inference_new_feature.py -vStep 2: Implement the module
# Create the inference module
touch src/forgesyte_yolo_tracker/inference/new_feature.py
# Implement functions to pass tests
# Use sports.common when available (MIT License)Step 3: Verify tests pass
uv run pytest src/tests/test_inference_new_feature.py -v| Type | Pattern | Example |
|---|---|---|
| Unit tests | test_*.py |
test_player_detection.py |
| Integration tests | src/tests/integration/test_*.py |
test_team_integration.py |
| Utils tests | src/tests/utils/test_*.py |
test_soccer_pitch.py |
For tests requiring YOLO models (always skip on CPU):
"""Tests for new feature inference module."""
import os
import pytest
import numpy as np
from unittest.mock import MagicMock, patch
RUN_MODEL_TESTS = os.getenv("RUN_MODEL_TESTS", "0") == "1"
pytestmark = pytest.mark.skipif(
not RUN_MODEL_TESTS,
reason="Set RUN_MODEL_TESTS=1 to run (requires YOLO model)"
)
class TestNewFeatureJSON:
"""Tests for detect_new_feature_json function."""
def test_returns_dict(self) -> None:
"""Verify returns dictionary."""
from forgesyte_yolo_tracker.inference.new_feature import detect_new_feature_json
frame = np.zeros((480, 640, 3), dtype=np.uint8)
result = detect_new_feature_json(frame, device="cpu")
assert isinstance(result, dict)
def test_returns_expected_keys(self) -> None:
"""Verify returns expected keys."""
from forgesyte_yolo_tracker.inference.new_feature import detect_new_feature_json
frame = np.zeros((480, 640, 3), dtype=np.uint8)
result = detect_new_feature_json(frame, device="cpu")
assert "detections" in resultplugins/forgesyte-yolo-tracker/src/forgesyte_yolo_tracker/
├── plugin.py # ForgeSyte-native functions (no class)
├── manifest.json # Tool schema
├── inference/ # Frame-based JSON modes
│ ├── player_detection.py # detect_players_json(), *_with_annotated_frame()
│ ├── player_tracking.py # track_players_json(), *_with_annotated_frame()
│ ├── ball_detection.py # detect_ball_json(), *_with_annotated_frame()
│ ├── team_classification.py # classify_teams_json(), *_with_annotated_frame()
│ ├── pitch_detection.py # detect_pitch_json(), *_with_annotated_frame()
│ └── radar.py # radar_json(), radar_json_with_annotated_frame()
├── video/ # Video processing modes
│ └── *_video.py # run_*_video_frames(), run_*_video()
├── utils/ # Utilities
│ ├── ball.py # BallTracker
│ ├── soccer_pitch.py # Soccer pitch drawing
│ └── (imports from sports.common)
├── configs/
│ └── soccer.py # SoccerPitchConfiguration
└── models/ # Model files
├── football-player-detection-v3.pt
├── football-ball-detection-v2.pt
└── football-pitch-detection-v1.pt
| Decision | Value |
|---|---|
| Team colors | Team A: #00BFFF, Team B: #FF1493, GK: #FFD700, Ref: #FF6347 |
| Confidence defaults | Player: 0.25, Ball: 0.20, Pitch: 0.25 |
| Radar resolution | 600×300 px, pitch: 12000×7000 cm |
| Team classification | On-the-fly (collect → UMAP → KMeans → predict) |
| Model versions | player-v3, ball-v2, pitch-v1 |
# Check Python version
python --version
# List installed packages
uv pip list
# Freeze requirements
uv pip freeze > requirements.txt
# Create requirements.txt for plugin
cd plugins/forgesyte-yolo-tracker
uv pip freeze > requirements.txtfrom forgesyte_yolo_tracker.inference.player_detection import (
detect_players_json,
detect_players_json_with_annotated_frame,
)from forgesyte_yolo_tracker.video.player_detection_video import (
run_player_detection_video_frames,
run_player_detection_video,
)
# Generator pattern for frames
for annotated_frame in run_player_detection_video_frames(source, device="cpu"):
process(annotated_frame)
# Full video pipeline
run_player_detection_video(source, target, device="cpu")from sports.common import TeamClassifier, ViewTransformer, create_batchesTests requiring GPU should be run on Kaggle with CUDA available:
git clone https://github.com/rogermt/forgesyte-plugins.git
cd forgesyte-plugins/plugins/forgesyte-yolo-tracker
# Install with GPU support
uv pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118
uv pip install -e .
# Download model files to models/
# football-player-detection-v3.pt
# football-ball-detection-v2.pt
# football-pitch-detection-v1.pt
# Run contract tests only (fast, CI-safe)
make test-fast
# Run heavy tests only
make test-heavy
# Run all tests (contract + heavy)
make test-all
# Run with coverage (excludes model internals)
pytest tests_contract tests_heavy -v --cov --cov-report=term-missingTests are now organized into two categories:
tests_contract/- Fast, mocked, plugin-API tests (run in CI, ~90 tests, 2 min)tests_heavy/- Model-dependent, inference tests (optional, ~200 tests, 15 min)
Why this structure:
- CI runs only contract tests (fast, stable)
- Heavy tests preserved for debugging/research
- Coverage measures plugin contract, not YOLO internals
- Professional separation of concerns
See /docs/design/TEST_FLOW.md for architecture diagram.
- Follow PEP 8
- Use type hints
- Run
ruff check src/ --fixbefore committing - Add docstrings to all public functions
- Keep functions small and focused
- Use mocking for CPU tests (no model loading)
<type>(<scope>): <subject>
<body>
footer
Types: feat, fix, refactor, docs, chore, test
Example:
feat(yolo-tracker): Add player detection inference module
Implement detect_players_json() and detect_players_json_with_annotated_frame()
Closes #32
- See
README.mdfor plugin documentation - See
docs/development/for general guidelines - Check existing tests in
src/tests/for patterns
Goal: Integrate YOLO tracker with forgesyte web-ui for real-time video streaming
Status: Web-UI integration in progress (see forgesyte/AGENTS.md)
✅ No plugin code changes required — your plugin is already compatible!
- Manifest is frozen (no changes)
- Tool functions remain as-is (player_detection, player_tracking, etc.)
- Frame input/output contracts are stable
- Discover your tools from manifest.json
- Call
/plugins/{id}/tools/{tool}/runwith base64 frames - Render results using generic canvas overlays
- Week 3: GPU tests on Kaggle with real YOLO models
- Command:
RUN_MODEL_TESTS=1 pytest tests/integration/
- Your tools: player_detection, player_tracking, ball_detection, pitch_detection, radar
- Your manifest: Defines input/output contracts (don't modify)
- Your tests: Keep them passing (CPU-only in CI, GPU on Kaggle)