Skip to content

Latest commit

 

History

History
142 lines (98 loc) · 5.38 KB

File metadata and controls

142 lines (98 loc) · 5.38 KB

Contributing to ARGUS

Before you start

  • Open an issue first for non-trivial changes so the approach can be discussed.
  • Every PR must pass CI (backend tests + frontend build) before review.
  • No dead code, no stale comments, no magic numbers — all tuneable values belong in backend/config.py or .env.

Setup

Backend

cd backend
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
uvicorn main:app --reload

.env belongs at the project root (alongside docker-compose.yml), not inside backend/. The backend searches ../ automatically.

For PostgreSQL support, also install:

pip install -r backend/requirements-postgres.txt

Frontend

cd frontend
npm install
npm run dev

The Vite dev server proxies /api/* to http://localhost:8000 — run both simultaneously.

Running tests

# From repo root
python -m pytest tests/ -v
# Frontend type-check and build
cd frontend && npm run build

Commit format

Use imperative present tense in the subject line. Keep it under 72 characters.

<type>: <short summary>

<optional body — wrap at 72 chars>

Types: feat, fix, refactor, test, docs, chore

Examples:

feat: add Shodan source plugin
fix: handle empty stream URL in frame fetch
docs: update AI configuration table

A .gitmessage template is included in the repo root. To use it locally:

git config commit.template .gitmessage

Code conventions

Backend

  • All HTML extraction belongs in the source's own private module (e.g. sources/insecam/_parse.py). No source-specific parsing logic in backend/utils/.
  • All HTTP setup belongs in backend/utils/http.py.
  • Routes must not import source modules directly — the background thread spawned by _run_scrape is the only caller of scrape().
  • Pydantic models are the single source of truth for data shapes. No ad-hoc dicts crossing the API boundary.
  • Type annotations required on all public functions.
  • CountryMeta and any other source-specific model belongs inside the source package, not in backend/models/.

Frontend

  • All API calls live in src/utils/api.ts. Components never call fetch directly.
  • State that spans multiple components lives in App.tsx or a hook. Components receive props.
  • No inline style objects defined inside JSX — keep them in the styles constant at the bottom of each file.
  • lucide-react icons only — no other icon libraries.

AI features

Enabling AI

Set AI_ENABLED=true and OPENAI_API_KEY=<your key> in .env. AI is opt-in and off by default. All other AI env vars have sane defaults (see .env.example).

Any OpenAI-compatible endpoint works — set OPENAI_BASE_URL to point at OpenRouter, Ollama, or any other compatible provider.

Cost policy

  • Scene analysis and intelligence briefs are always user-triggered — nothing runs automatically.
  • Bulk queue workers default to 3 concurrent jobs (AI_QUEUE_WORKERS). Keep this low during development.
  • Scene analysis uses detail: "low" for image inputs (cheaper, sufficient for surveillance frames).
  • Intelligence briefs are capped at 600 tokens (_INTEL_MAX_TOKENS in ai/service.py).
  • Re-running analysis overwrites the previous result — no history is kept.
  • fetch_frame validates that a complete JPEG was received (SOI \xff\xd8 and EOI \xff\xd9 both present). A partial frame returns None, which marks the queue job failed rather than sending corrupted image data to the model.

Prompt conventions

  • All system prompts live in backend/ai/prompts.py as module-level constants. Never inline a prompt in a service method or route.
  • Prompts use plain English imperative style. Brevity over length — the models are called for many cameras.
  • When updating prompts, include a brief comment explaining the intent of any non-obvious instruction.

Queue contract

  • Every scene analysis job goes through analysis_queue — single camera or bulk, same code path.
  • analysis_queue.add(ids) is idempotent for pending/processing cameras. Re-adding a done/failed camera re-queues it (retry semantics).
  • Workers auto-start when cameras are added via addCamerasToQueue in useAnalysisQueue.ts. The POST /ai/queue/start endpoint is idempotent — safe to call when workers are already running.
  • Workers use asyncio.run() to call async AI methods — each worker thread owns its own event loop.
  • ai.service and api.store are imported lazily inside _worker_loop to avoid circular imports.
  • State transitions: pending → processing → done | failed. Every transition emits a QueueProgressEvent over SSE.

Adding a new AI feature

See the "Adding a new AI feature" section in AGENTS.md for the step-by-step checklist.


Scraper etiquette

  • Never remove the scraper_page_delay between country batches.
  • Do not increase default scraper_workers above 20 in PRs — respect the source's infrastructure.
  • The scraper must remain read-only: no writes, no authentication attempts, no form submissions.

Pull request checklist

  • CI passes (backend tests + frontend build)
  • No new TODO or FIXME comments without a linked issue
  • Docstrings updated on any modified public functions
  • If the Camera, ScrapeProgress, or SourceMeta model changed: both backend/models/ and frontend/src/types/index.ts are updated in the same PR