1
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Contributing to PlanOpticon
2
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
3
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Thank you for your interest in contributing to PlanOpticon! This guide will help you get started.
4
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
5
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Development Setup
6
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
7
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1. **Fork and clone the repository:**
8
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
9
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
10
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
git clone https://github.com/<your-username>/PlanOpticon.git
11
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cd PlanOpticon
12
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
13
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
14
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2. **Create a virtual environment:**
15
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
16
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
17
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
python -m venv .venv
18
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
source .venv/bin/activate # On Windows: .venv\Scripts\activate
19
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
20
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
21
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
3. **Install in editable mode with dev dependencies:**
22
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
23
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
24
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
pip install -e ".[dev]"
25
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
26
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
27
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
4. **Install FFmpeg** (required for video processing):
28
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
29
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
30
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# macOS
31
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
brew install ffmpeg
32
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
33
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Ubuntu/Debian
34
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
sudo apt install ffmpeg
35
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
36
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
37
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
5. **Set up at least one AI provider API key:**
38
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
39
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
40
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
export OPENAI_API_KEY="sk-..."
41
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# or
42
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
export ANTHROPIC_API_KEY="sk-ant-..."
43
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# or
44
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
export GEMINI_API_KEY="..."
45
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
46
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
47
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Running Tests
48
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
49
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
50
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
pytest tests/
51
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
52
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
53
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
To run tests with coverage:
54
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
55
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
56
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
pytest tests/ --cov=video_processor
57
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
58
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
59
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Code Style
60
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
61
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
This project uses [Ruff](https://docs.astral.sh/ruff/) for linting and formatting.
62
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
63
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**Check for lint issues:**
64
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
65
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
66
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ruff check .
67
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
68
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
69
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**Auto-fix lint issues:**
70
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
71
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
72
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ruff check --fix .
73
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
74
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
75
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**Format code:**
76
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
77
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
78
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ruff format .
79
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
80
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
81
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**Verify formatting (without modifying files):**
82
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
83
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
84
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ruff format --check .
85
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
86
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
87
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
The project targets a line length of 100 characters and Python 3.10+. See `pyproject.toml` for the full Ruff configuration.
88
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
89
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Commit Conventions
90
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
91
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Write clear, descriptive commit messages. Use the imperative mood in the subject line:
92
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
93
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- `Add knowledge graph merging for batch mode`
94
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- `Fix frame extraction crash on zero-length videos`
95
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- `Update API provider discovery to handle rate limits`
96
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
97
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Keep the subject line under 72 characters. Use the body to explain *what* and *why*, not *how*.
98
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
99
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Pull Request Process
100
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
101
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1. **Create a branch** from `main` for your work:
102
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
103
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
104
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
git checkout -b your-branch-name
105
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
106
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
107
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2. **Make your changes.** Write tests for new functionality and ensure existing tests still pass.
108
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
109
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
3. **Lint and format** your code before committing:
110
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
111
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
112
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ruff check .
113
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ruff format .
114
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
115
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
116
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
4. **Push your branch** and open a pull request against `main`.
117
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
118
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
5. **Fill out the PR template.** Describe your changes, the type of change, and your test plan.
119
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
120
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
6. **Address review feedback.** A maintainer will review your PR and may request changes. We aim to review PRs within a few business days.
121
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
122
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Reporting Bugs and Requesting Features
123
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
124
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Bugs:** Open an issue using the [Bug Report](https://github.com/ConflictHQ/PlanOpticon/issues/new?template=bug_report.yml) template.
125
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Features:** Open an issue using the [Feature Request](https://github.com/ConflictHQ/PlanOpticon/issues/new?template=feature_request.yml) template.
126
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Questions:** Start a thread in [Discussions](https://github.com/ConflictHQ/PlanOpticon/discussions).
127
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
128
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Code of Conduct
129
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
130
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
This project follows a [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold it.
131
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
132
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Security
133
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
134
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
If you discover a security vulnerability, please do **not** open a public issue. Instead, follow the process described in our [Security Policy](SECURITY.md).
135
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
136
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## License
137
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
138
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
By contributing to PlanOpticon, you agree that your contributions will be licensed under the [MIT License](../LICENSE).
139
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!