Files
zoneminder/AGENTS.md
T
Isaac ConnorandClaude Opus 5 5c060bb6e6 chore: drop the libvlc build dependency from packaging, CI and docs
Nothing links or dlopens libvlc any more, so the dev package is no
longer a build requirement anywhere: the debian, beowulf, ubuntu and
split-package control files, the podman Containerfile, the redhat and
opensuse specs, the centos CI image, and the five workflows that
installed libvlc-dev. The redhat spec also required vlc-core at
runtime, which was the dlopen target.

Documentation follows: the libVLC source tab section, the macos note
about libVLC not being found, and the WEB_FILTER_SOURCE source-type
list.

Two stale statements nearby are corrected while the files are open. The
Remote source tab still said its RTSP method "may be removed in the
future"; it was removed earlier on this branch. AGENTS.md still listed
RemoteCameraRTSP and LibVLCCamera among the camera classes, both of
which are now gone.

All workflow yaml parses, the three edited rst files render, and the
debian control field structure is unchanged apart from the removed
entries.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Y6FieTwEXuLhhR4e2yiax
2026-10-10 09:32:17 -04:00

336 lines
13 KiB
Markdown

# AI Agent Development Guide for ZoneMinder
> **Note**: This file guides AI coding agents (Claude Code, GitHub Copilot, Cursor, etc.) working on ZoneMinder.
> CLAUDE.md is a symlink to this file.
## Quick Reference (MANDATORY RULES)
1. **Testing First**: Write tests BEFORE/DURING implementation - NEVER skip. Tests written "later" never get written.
2. **Build System**: CMake with C++17, out-of-source builds in `build/`. In-source builds pollute the repo.
3. **Feature Workflow**: GitHub Issue -> Feature Branch -> Implement FULLY -> Tests Pass -> Get Approval -> Merge to master. Feature branches keep master stable.
4. **Commits**: Conventional format (`feat:`/`fix:`/`test:`), reference issues (`refs #n` or `fixes #n`). Enables automated changelog.
5. **Pre-Commit**: Tests pass, build succeeds, linting clean, no warnings.
6. **Never merge without user approval. Never leave features half-implemented.**
---
## What is ZoneMinder?
Linux-based CCTV surveillance system: capture, analysis, recording, and monitoring of video cameras.
- **C++ daemons** (`src/`) - Capture (`zmc`), analysis (`zma`), streaming (`zms`), utility (`zmu`)
- **PHP web interface** (`web/`) - Bootstrap + jQuery UI, AJAX endpoints in `web/ajax/`, views in `web/views/`
- **REST API** (`web/api/`) - CakePHP 2.x, controllers in `web/api/app/Controller/`, JWT auth
- **Perl scripts** (`scripts/`) - Daemon control (`zmdc.pl`), migrations (`zmupdate.pl`), filtering (`zmfilter.pl`)
- **MySQL database** (`db/`) - Schema in `db/zm_create.sql.in`, migrations in `db/zm_update-*.sql` (60+ versions)
---
## Architecture
### Data Flow
```
Camera -> zmc (capture) -> Shared Memory -> zma (analysis) -> Event Recording
| |
zms (streaming) Database + Disk
| |
Web Browsers <- Web Interface/API <- MySQL Storage
```
### Key Patterns
- **Shared Memory**: `zmc` writes frames to `/dev/shm`; `zma` and `zms` read from same buffers. Zero-copy for performance — this is why ZM can handle many cameras on modest hardware.
- **Monitor-Centric**: `Monitor` class (`src/zm_monitor.cpp/h`) is the central orchestrator. One monitor = one DB row = one set of daemons. Most changes to camera handling flow through this class.
- **Pluggable Cameras**: Abstract `Camera` base with: `LocalCamera` (V4L2), `RemoteCameraHTTP`, `FFmpegCamera`, `LibVNCCamera`. Add new camera types by subclassing Camera.
- **Event-Driven Recording**: Motion detection triggers `Event` objects with pre/post alarm buffers. Lifecycle: Create -> Record -> Close -> Archive/Delete. Events are the core unit of recorded footage.
- **Multi-Server Clustering**: Database-coordinated distributed architecture with shared monitors and storage.
### Directory Structure (Key Paths)
```
src/ C++ core (86+ source files): zm_monitor.*, zm_camera.*, zm_event.*, zm_zone.*, zm_image.*, zm_ffmpeg*.*
web/ PHP web interface
ajax/ AJAX handlers
includes/ PHP libraries and functions
views/ UI templates
skins/ Themes (classic skin)
js/, css/ Frontend assets
api/app/Controller/ CakePHP REST API controllers
api/app/Model/ CakePHP REST API models
scripts/ Perl system management (.in templates)
db/ Schema (zm_create.sql.in) and migrations (zm_update-*.sql)
tests/ Catch2 unit tests + test data
misc/ Server configs (apache, nginx, systemd)
dep/ Vendored deps (catch2, jwt-cpp)
.github/workflows/ CI/CD pipelines
```
---
## Development Workflow (MANDATORY)
### For every feature or bug fix:
1. **Create GitHub Issue**: `gh issue create --title "..." --label enhancement|bug`
2. **Create Feature Branch**: `git checkout -b <issue>-<description>` from master
3. **Write failing test first** (TDD)
4. **Implement** - follow existing patterns, keep changes minimal
5. **Build & test** - must all pass (see Build and Testing sections)
6. **Commit** in logical chunks with conventional messages
7. **Request user approval** - never merge without it
8. **After approval**: merge to master, delete branch, push, verify issue closes
### Technology-Specific Notes
- **C++ changes** (`src/`): Rebuild required, run ctest. Daemons must be restarted to pick up changes.
- **PHP/JS changes** (`web/`): No rebuild needed — PHP is interpreted, changes are live immediately. Test in browser + ESLint.
- **Database schema** (`db/`): Create migration file `zm_update-X.X.X.sql` for existing installs, also update `db/zm_create.sql.in` for fresh installs. Both must result in the same schema.
- **Perl scripts** (`scripts/`): Edit `.in` template files (NOT generated scripts). cmake substitutes `@ZM_*@` variables to produce the final scripts. When testing perl changes, any perl script will try to read /etc/zm/zm.conf and needs to be run as a user with permission to read it. Best to run with sudo -u www-data
- **API changes** (`web/api/`): Clear CakePHP cache (`tmp/cache/`) if you change models or routes. Test endpoints with curl.
### Example Workflow
```bash
gh issue create --title "Add event favorites" --label enhancement
# Note issue number, e.g. #42
git checkout master && git pull && git checkout -b 42-event-favorites
# Write test first, implement, build & test
cd build && cmake --build . && ctest
npx eslint .
# Commit
git add <files>
git commit -m "feat: add favorites toggle to event view refs #42"
# Ask user for approval, then after approval:
git checkout master && git merge 42-event-favorites
git push origin master
git branch -d 42-event-favorites && git push origin --delete 42-event-favorites
```
---
## Build System
```bash
# Standard build (out-of-source required)
mkdir build && cd build
cmake ..
cmake --build .
# Debug build with tests
cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TEST_SUITE=ON ..
cmake --build .
# Build specific target
cmake --build . --target zmc
```
### Key CMake Options
| Option | Values | Default | Notes |
|--------|--------|---------|-------|
| `CMAKE_BUILD_TYPE` | Release/Debug/Optimised/Profile | Release | `Profile` = `-O2 -g -fno-omit-frame-pointer` for perf/flamegraph |
| `BUILD_TEST_SUITE` | ON/OFF | OFF | Enables Catch2 tests |
| `ENABLE_WERROR` | ON/OFF | OFF | Warnings as errors (CI uses ON) |
| `ASAN` | ON/OFF | OFF | AddressSanitizer |
| `TSAN` | ON/OFF | OFF | ThreadSanitizer (mutually exclusive with ASAN) |
| `ZM_CRYPTO_BACKEND` | openssl/gnutls | | |
| `ZM_JWT_BACKEND` | libjwt/jwt_cpp | | |
| `ZM_TARGET_DISTRO` | FreeBSD/fc/el/OS13 | (Debian) | Platform-specific paths |
| `ZM_ONVIF` | ON/OFF | ON | ONVIF camera support |
---
## Testing Requirements (MANDATORY)
### Workflow
1. Write a failing test that reproduces the issue or validates the feature
2. Implement the fix/feature
3. Run tests - verify they PASS
4. Run full test suite for regressions
5. Only then commit
### C++ Unit Tests (Catch2)
```bash
# Build with tests
cmake -DBUILD_TEST_SUITE=ON .. && cmake --build .
# Run all tests
ctest
# Or directly with more output
./tests/tests
# Run specific test / list tests
./tests/tests "[Box]"
./tests/tests --list-tests
./tests/tests "~[notCI]"
```
**Test location**: `tests/` directory
**Existing modules**: `zm_box.cpp`, `zm_comms.cpp`, `zm_crypt.cpp`, `zm_font.cpp`, `zm_poly.cpp`, `zm_utils.cpp`, `zm_vector2.cpp`
**Framework**: Catch2 with custom header `tests/zm_catch2.h`, main in `tests/main.cpp`
**Test data**: `tests/data/fonts/`
### JavaScript Linting
```bash
npx eslint . # Lint all
npx eslint --fix web/js/ # Auto-fix
```
ESLint config: `eslint.config.js` (ESLint 9 flat config, Google style guide). Runs in CI via `.github/workflows/ci-eslint.yml`.
### PHP/API Testing
Manual testing required. Test endpoints with curl/browser. Verify JSON responses, auth (session + JWT), error handling, DB persistence.
### Database Migration Testing
```bash
sudo zmupdate.pl --check # Check for updates
sudo zmupdate.pl # Apply migrations
```
When creating migrations: test upgrade path AND verify fresh install matches migrated schema.
### CI Notes
- Unit tests are **DISABLED** in CI (`BUILD_TEST_SUITE=0`) — some tests need hardware/network access. Running locally goes beyond CI requirements but is still expected for local development.
- CI does: multi-platform builds (Debian/Ubuntu/CentOS with GnuTLS/OpenSSL + libjwt/jwt_cpp matrix), ESLint, CodeQL security scanning
---
## Code Standards
### C++ (`src/`)
- **C++17** standard, follow existing patterns in file/module
- **Memory**: RAII, smart pointers where appropriate
- **Error handling**: Exceptions for exceptional cases, return codes for expected errors
- **Logging**: Use printf-style `Debug(1, "msg %s", val)`, `Info(...)`, `Warning(...)`, `Error(...)`, `Fatal(...)` — NOT iostream style. The number in Debug() is verbosity level (1-9).
### PHP (`web/`, `web/api/`)
- PSR-12 where practical, follow existing conventions
- **Security**: Validate ALL user input, use prepared statements (NOT string interpolation — legacy code has SQL injection bugs we're fixing), sanitize output with htmlspecialchars/json_encode, CSRF protection on forms
- CakePHP 2.x framework in `web/api/` — we're stuck on 2.x due to migration cost, don't try to upgrade it
### JavaScript (`web/js/`, inline in PHP)
- Google JavaScript Style Guide (ESLint configured)
- jQuery + Bootstrap (legacy codebase), ES6+ where browser support allows
### Perl (`scripts/`)
- Edit `.in` template files, NOT generated scripts — cmake substitutes variables like `@ZM_LOGDIR@` to produce the final scripts
- Use `ZoneMinder::` modules, `ZoneMinder::Logger` for logging
- Rerun cmake after editing `.in` files to regenerate the actual scripts
---
## Commit Standards
**Conventional format** with issue references:
```
feat|fix|test|docs|chore|refactor|perf|style: description refs #N
```
- `refs #N` references issue; `fixes #N` closes it
- Imperative mood ("add feature" not "added feature")
- Be detailed and descriptive, no vague summaries
- One logical change per commit
- **No superlative language** ("comprehensive", "critical", "major", "massive") — AI agents tend to use these; they make commit logs unreadable
- Split unrelated changes into separate commits — makes bisecting and reverting possible
---
## Pre-Commit Checklist (Single Source of Truth)
Before committing or claiming complete:
- [ ] Tests written/updated BEFORE or DURING implementation
- [ ] Build succeeds: `cmake --build .` (C++ changes)
- [ ] C++ tests pass: `ctest` or `./tests/tests`
- [ ] JavaScript linting passes: `npx eslint .`
- [ ] Manual testing done (PHP/web changes)
- [ ] No compiler warnings or linter errors
- [ ] Code follows existing patterns
- [ ] Commit messages follow conventional format with issue reference
- [ ] Feature is COMPLETE (not half-implemented)
- [ ] State which tests were run and their results
**NEVER commit if**: tests failing, tests missing for new code, build fails, warnings exist, feature incomplete.
---
## Debugging Quick Reference
```bash
# Debug build
cmake -DCMAKE_BUILD_TYPE=Debug .. && cmake --build .
# AddressSanitizer
cmake -DCMAKE_BUILD_TYPE=Debug -DASAN=ON .. && cmake --build .
# Debug logging
export ZM_DBG_LEVEL=9 ZM_DBG_LOG=/tmp/debug.log
./src/zmc -m 1
# Log locations: /var/log/zm/ (zmc_m1.log, zma_m2.log, etc.)
# Runtime log level: kill -USR1 <pid> (increase) / kill -USR2 <pid> (decrease)
```
---
## Contributing (For Humans)
- **Bug reports & features**: [GitHub Issues](https://github.com/ZoneMinder/zoneminder/issues) (read [posting rules](https://github.com/ZoneMinder/ZoneMinder/wiki/Github-Posting-Rules) first)
- **Support**: [Forums](https://forums.zoneminder.com), [Slack](https://zoneminder-chat.slack.com), [Discord](https://discord.gg/tHYyP9k66q)
- **PRs**: Fork -> feature branch -> implement + test -> PR. Maintainers merge after review.
- **Docs**: https://zoneminder.readthedocs.org (source in `docs/`)
---
## grepai - Semantic Code Search
**Use grepai as PRIMARY tool for code exploration and search.**
### When to Use grepai (REQUIRED)
Use `grepai search` INSTEAD OF Grep/Glob for:
- Understanding what code does or where functionality lives
- Finding implementations by intent ("authentication logic", "error handling")
- Exploring unfamiliar parts of the codebase
Only use Grep/Glob for exact text matching (variable names, imports, specific strings) or file path patterns.
If grepai fails (not running, index unavailable), fall back to Grep/Glob.
### Usage
```bash
grepai search "user authentication flow" --json --compact
grepai search "JWT token validation" --json --compact
```
### Call Graph Tracing
```bash
grepai trace callers "HandleRequest" --json
grepai trace callees "ProcessOrder" --json
grepai trace graph "ValidateToken" --depth 3 --json
```
### Workflow
1. `grepai search` to find relevant code
2. `grepai trace` to understand function relationships
3. `Read` tool to examine files from results
4. Grep only for exact string searches if needed