Roadmap — BirdLense Hub
Direction of travel and current stack. Shipped items are summarized here; details live in Changelog and FEATURES.
Current stack (April 2026)
| Component | Version / note |
|---|---|
| Ultralytics | 8.4.33 at runtime (app/processor/requirements.txt, installed via pip in the image). Base image remains ultralytics/ultralytics:8.4.21 (newer base tags broke ngx_brotli build against nginx in CI; see CHANGELOG 0.3.1). |
| Platform | x86/amd64 only (Intel or AMD 64-bit). ARM / Apple Silicon / aarch64 — not supported, not planned |
| Detection | two_stage: binary .pt + YOLO11n-cls (EU); single_stage fallback if weights missing |
| EU classifier | best.pt — birds-525 + iNaturalist (~491 species) |
| US classifier | best_US.pt — NABirds (fallback) |
| React | 19.2.4 |
| Vite | 6.4.1 |
Recently delivered (high level)
- Home Assistant — MQTT discovery (e.g. last species, bird-detected). See CONFIGURATION → MQTT.
- Dataset pipeline —
best_framein YOLO layout, ZIP export (GET /api/ui/dataset/export), relabel moves on-disk crops. System → Storage. - Video prev/next (same UTC day) — #82 closed (v0.2.6):
GET /api/ui/videos/:id/neighbors+ arrows on video details (browse clips for that calendar day in UTC without losing list context). - Overview mean recording duration — #107 closed: metric is the average length of one clip (
Video), not a visit aggregate; PR #106. - Public gallery (opt-in) — #80 closed (v0.2.4): background upload runs inside Flask app context; troubleshooting in CONFIGURATION → Gallery.
- System: resource charts with server-side history — SQLite
system_resource_sample,GET /api/ui/system/metrics/history, UI windows 6/24/48 h plus live tail; tune withBIRDLENSE_SYSTEM_METRICS_*— CONFIGURATION → Prometheus / Grafana.
Backlog consilium (March 2026)
Brainstorm roles: product (operator value), security, platform/infra, ML & data, integrations (MQTT/HA/Frigate), UX, docs & OSS hygiene.
Outcome: triaged items are GitHub Issues (not shipped until closed in a release): #46–#48, #50–#57, #81 (operator UX — Mar 2026; phase B: Unknowns snackbar Open video). Done: #47 (git-history secret scan + SECURITY updates), #48 (export_birdlense_to_yolo.py), #50 (MQTT reconnect backoff + missed-events docs clarity), #51 (SQLite backup/restore in System UI + INSTALL/TROUBLESHOOTING updates), #52 (locale switch + pilot de locale), #53 (scheduled smoke for published ghcr image), #54 (OpenAPI contract smoke in CI + local run command), #80 (gallery upload thread app context, v0.2.4), #82 (same-UTC-day video prev/next, v0.2.6), #85 (local TZ / cross-day / docs), #107 (Overview: mean duration = per-Video average, not visit span). #49 (ARM Docker) is closed — x86-only; not part of this backlog.
Put them on the Project board: OAuth scopes often loop on device login — use a classic PAT (repo + project) in GH_TOKEN or scripts/.env.project (see scripts/env.project.example), then:
bash scripts/github-project-add-backlog-consilium.sh
All open issues/PRs: bash scripts/github-project-import-open-items.sh. Or add cards manually in the GitHub UI.
Status/assignee/checklist sync: bash scripts/github-project-sync.sh --assign Gfermoto.
| # | Theme | Issue | Labels (summary) |
|---|---|---|---|
| 1 | Rate limiting for settings / auth API | #46 ✅ verify-password, docs, tests |
area:web, P2 |
| 2 | Git history secret scan (maintainer) | #47 ✅ gitleaks script + SECURITY EN/RU | area:infra, P3, documentation |
| 3 | export_birdlense_to_yolo.py training export |
#48 ✅ YOLO cls train/val export script |
area:processor, P2 |
| 4 | MQTT reconnect / missed-events clarity | #50 ✅ reconnect backoff + docs | area:processor, P2 |
| 5 | UI: backup / restore SQLite | #51 ✅ System backup/restore + docs | area:web, P3 |
| 6 | UI i18n framework | #52 ✅ locale switch + pilot de |
area:web, P3 |
| 7 | CI: scheduled image smoke test | #53 ✅ workflow Docker image smoke (published) (ghcr ... :latest + /api/ui/health) |
area:infra, P3 |
| 8 | CI: OpenAPI contract tests | #54 ✅ openapi-contract in CI + web/tests/test_openapi_contract.py |
area:web, P3 |
| 9 | Yearly species checklist / life list | #55 ✅ Migration page: year filter + table (rows and Σ) — no duplicate checklist block | area:web, P3 |
| 10 | CORS demo host → config/env | #56 ✅ demo host moved out of hardcoded CORS defaults into CORS_DEFAULT_ORIGINS / CORS_ORIGINS |
area:web, P3 |
| 11 | Docs: Prometheus alert examples | #57 ✅ examples/prometheus/, CONFIGURATION |
area:docs, P3 |
| 12 | Gallery: investigate / fix (opt-in public gallery) | #80 ✅ app context in upload thread + docs/tests v0.2.4 | area:web, P2, bug |
| 13 | Manual species correction: unify Unknowns vs in-video flow | #81 ✅ phases A+B+C: shared API + Unknowns Open video snackbar + recent shared correction history | area:web, P2 |
| 14 | Video navigation: sequential browse (e.g. same day), no list reset | #82 ✅ UI + GET /videos/:id/neighbors v0.2.6 |
area:web, P2 |
| 15 | Video neighbors: local TZ, cross-day jump, docs clarity (follow-up to #82) | #85 ✅ local day + cross_day + API/UI docs |
area:web, P3 |
| 16 | Overview: “mean duration” used visit span instead of per-recording average | #107 ✅ mean over Video rows (PR #106); RU/EN labels |
area:web, P3, bug |
| 17 | Detection: false positives and inanimate objects — strategy (two_stage vs single_stage+COCO, thresholds, weights) | Consilium: § below · ties to #163 | P2, processor, ML |
Detection strategy consilium
Goal: run a consilium (product/operator, ML, platform) and record a decision on reducing false positives and non-living object detections in production. By default this runs after the current development wave is closed and basic manual acceptance; see § Finish work, then operator testing.
Context: with detection_strategy: two_stage and values in user_config.yaml, behavior does not match single_stage + typical COCO, where the default animals-only auto-filter applies (processor.single_stage_coco_animals_only_auto — excludes person and inanimate COCO classes). Deploying code does not overwrite user_config.yaml.
Options to compare (combinations allowed):
- keep two_stage and tune
min_confidence_binary/min_confidence_to_process, and/or retrain/replace the binary detector; - move to single_stage + COCO (or another detect model) and rely on the animal filter / custom classes;
- factor in Frigate / extra motion triggers.
See CONFIGURATION.md (processor, motion). Non-bird classes overlap #163 — consilium should decide one epic vs child issues.
Do not forget (checklist):
| Step | Action |
|---|---|
| 1 | Capture the live hub processor snippet from user_config.yaml: detection_strategy, models.binary / models.classifier / models.single_stage, min_confidence_binary, min_confidence_to_process, single_stage_coco_animals_only_auto. |
| 2 | Note symptoms: what triggers false positives / non-animal detections (scene, time of day, weather when possible). |
| 3 | At the consilium, pick an approach (two_stage + thresholds/model or single_stage + COCO/custom or Frigate hybrid, etc.) and write the decision into Issue(s) (one epic or children). |
| 4 | After the decision: update this ROADMAP (row 17 — outcome or link to closed issue), CONFIGURATION / examples if keys change; on the server edit user_config.yaml manually if needed (deploy does not overwrite it). |
| 5 | Keep in sync with #163 by explicit choice: one workstream or separate cross-linked issues. |
Triage: Issue vs. Discussion
| Use | When |
|---|---|
| GitHub Issue | Clear scope, definition of done, fits an area label (area:*) and priority — work can land on the Project board. |
| Discussions | Exploratory ideas, multiple design options, “should we at all?”, community input before committing. |
After consilium: new tracked work → create/update the Issue, add the card to the Project (github-project-add-backlog-consilium.sh or manually), then update this ROADMAP table in the same PR or follow-up.
Reporting (all shipped work, not only consilium): every shipped item has a GitHub Issue (open one if missing) and, when tracked, a card on BirdLense Hub — Roadmap. When done: comment (outcome + PR links), close the issue, set board Status → Done (with a PAT: bash scripts/github-project-mark-done.sh <n>). For routine hygiene, run bash scripts/github-project-sync.sh --assign Gfermoto (aligns board status/flow with issue state, assigns open issues without assignee, reports open issues missing subtask checklists). Checklist: root CONTRIBUTING.md § Issues & Project board. Deferred ideas may live only in this ROADMAP until a new scoped issue is filed.
Future work candidates
Prioritize by capacity; open a new GitHub issue when work is scoped (see CONTRIBUTING.md).
| Theme | Why |
|---|---|
| Accessibility (a11y) | #117 ✅ baseline v0.2.9: skip link, focus, contrast, axe E2E, A11Y.md; further work via new issues. |
| Broader E2E (Playwright) | #118 ✅ issue closed: smoke suites + scheduled CI — TESTING.md; more journeys added incrementally in PRs. |
| Secrets in production | #119 ✅: runbook SECRETS_ROTATION.md (complements #47). |
| Stack version sync | #120 ✅: checklist + python3 scripts/check-docs-version.py — see VERSIONING. |
| Community / donation UX | #121 ✅ MVP: general.donate_url drives links in Navigation (desktop + mobile + gear menu) and Food card; see CONFIGURATION.md. Click analytics out of scope. |
| Interactive life list (planning) | #125 ✅ issue closed: same intent — manual flags/notes vs migration table; open a new issue when a spec exists. |
| Species canonical registry | #168 ✅: unified registry, name normalization, backfill, background metadata jobs, CI quality gate for the full dataset. |
User wishes backlog (Mar 2026)
Tracked as separate issues; acceptance criteria live in each issue.
Preparation before coding (#131, #139): pre-implementation checklist.
Progress update (Mar 2026):
- #117 — a11y baseline shipped in v0.2.9 (PR #187, release #188); see A11Y.md.
- #139 — shipped and closed: Unknowns nav removed, /unknowns legacy redirect to /timeline?review=1, Timeline review mode (chip + counter), OpenAPI + API tests + smoke redirect coverage.
- #131 — shipped and closed: Catalog menu entry removed, legacy /species redirects to /migration-calendar, species deep links (/species/:id) preserved.
- #127 — shipped and closed: region comparison block moved from Overview to Migration; leftover Overview pointer removed.
- #130 — shipped and closed: Overview species distribution chart (slice and legend) now drills down to Timeline with species/date filters.
- #133 — shipped and closed: Migration page now supports day-level date-range filtering for the migration table while keeping regional reference block unfiltered.
- #129, #153, #157 — shipped and closed: BirdNET MQTT bias, multi-camera confidence boost, recording post-roll; see CONFIGURATION.md → Processor.
- #114, #118, #125, #163–#166 — issues closed for a zero-open backlog tail: UX gate in CONTRIBUTING.md, E2E note in TESTING.md, other ideas in the tables below + consilium item 17.
- #167 — open: scales integration shipped; backlog — sharp weight-change trigger and estimated bird weight on the visit/video card (like feeder/weather); optional auto-tare / detections later.
| # | Issue | Summary |
|---|---|---|
| #127 | Regional top + overlap with recognized | ✅ Compare-to-region on Migration (see progress above) |
| #128 | Auto thresholds for regional top | ✅ Processor merge + settings; delta/floor from min_confidence_to_process; manual overrides win; CONFIGURATION.md |
| #129 | Thresholds + MQTT BirdNET | ✅ Lower classifier thresholds for species in recent BirdNET MQTT: birdnet_mqtt_auto_confidence + window/delta; CONFIGURATION.md |
| #130 | Overview second chart | Click species → today’s recordings for that species |
| #131 | Migration as catalog entry | Remove catalog from nav; migration table primary path to species; clicks → /species/:id; in-page tabs = table modes |
| #139 | Unknowns + Timeline | Remove Unknowns nav; review mode on Timeline (chip + badge; redirect legacy URL) |
| #132 | Species filters | ✅ Bird Directory «Regional» = eBird regional top + birdnet_mqtt detections; regional_scope on GET /species; CONFIGURATION.md |
| #133 | Period on Migration | Day-level date range; table + heard/recognized; not regional |
| #134 | Food list for Europe | ✅ expanded seed.py + idempotent merge by name; CONFIGURATION.md → Bird food |
| #136 | eBird species_mapping |
✅ GET /api/ui/settings/ebird-species-mapping-suggestions, Settings UI button, shared eBird top cache; CONFIGURATION.md |
New ideas (Mar 2026) — table keeps historical GitHub numbers; open a new issue when work starts:
| # | Theme | Issue | Priority / area |
|---|---|---|---|
| 1 | System: unique visitor counter | #151 ✅ | P3, web |
| 2 | After deleting a recording, return to list not Home | #152 ✅ | P2, web, bug |
| 3 | Multi-camera confidence for cameras at one location | #153 ✅ multi_camera_groups + boost after merge; CONFIGURATION.md |
P2, processor |
| 4 | “Daily pattern” chart: click should filter by hour | #154 ✅ | P2, web, bug |
| 5 | Recording duration mismatch (Home vs recording page) | #155 ✅ | P2, web, bug |
| 6 | Review counter not updating without full reload | #156 ✅ | P2, web, bug |
| 7 | Recording quality: pre-roll/post-roll for approach/departure | #157 ✅ processor.post_record_seconds (recording tail); pre-roll remains video.pre_record_seconds (Go2RTC — see issue) |
P2, processor |
| 8 | Re-export: orphan recognitions without species/recording | #158 ✅ | P1, processor, bug |
| 9 | UX consistency: tooltips and inline help | #159 ✅ | P3, web |
| 10 | Regenerate tracks: progress, 409, timeouts on large sets | #160 ✅ | P1, web, bug |
| 11 | Dataset UX: clear Library flow (DB maintenance + export) | #161 ✅ | P2, docs + web |
| 12 | Dataset pipeline: less post-script work before training | #162 ✅ | P2, processor |
| 13 | Detector: non-bird classes (mice, squirrels, cats) | #163 ✅ issue closed; tracker: consilium item 17; new issue when training starts | P3, processor, research |
| 14 | Classifier: transfer learning (US + local dataset) | #164 ✅ issue closed; idea retained here; new issue when work starts | P2, processor, research |
| 15 | Telegram: SOCKS5h proxy in UI and MTProto (apihelper.proxy) |
#165 ✅ issue closed; idea retained here; new issue when work starts | P3, web |
| 16 | Heimdall integration | #166 ✅ issue closed; idea retained here; new issue when work starts | P3, infra |
| 17 | Scales: MQTT/HA + UI shipped; next — weight spike trigger + bird weight estimate on visit card (feeder/weather style); optional auto-tare + detections | #167 open | P3, processor, research |
System initiative (P1):
- #168 — Species Canonical Registry epic: canonical registry, universal name resolver, history migration, metadata enrichment, CI invariants (not one-off per-species patches).
- Phases closed: #169 ✅ SSOT registry · #170 ✅ universal resolver · #171 ✅ backfill/repair · #172 ✅ background metadata jobs · #173 ✅ observability + CI quality gate.
- Outcome (Mar 2026): production
processed=806,matched=806,unresolved=0on startup; APIsseed/backfill/unresolved/health/enrich, async enrichment status, CI smoke for the registry.
Shipped ideas (archive)
Historical simple → complex checklist (all rows shipped). Cross-check FEATURES; do not treat this table as a to-do list.
| Idea | Notes | Complexity |
|---|---|---|
| ✅ Playback speed 0.5× / 2× | Video player (VideoPlayer/index.tsx) |
Low |
| ✅ Webhook on detection | webhook.url + POST from processor |
Low |
| ✅ CSV/JSON timeline export | /api/ui/timeline/export + Timeline UI |
Low |
| ✅ “Last bird” Overview widget | See Overview | Low |
| ✅ Timeline time-of-day filter | Timeline (+ Unknowns) | Low |
| ✅ PWA improvements | Vite PWA, install prompt, update prompt | Low |
| ✅ Unknowns page | Low-confidence review | Medium |
| ✅ Monthly PDF report | System / reports | Medium |
| ✅ Xeno-canto on species page | Bird directory | Medium |
| ✅ eBird export | Timeline export menu | Medium |
| ✅ Prometheus / Grafana | /metrics, /api/metrics |
Medium |
| ✅ Per-species confidence overrides | Settings | Medium |
| ✅ iNaturalist crop export | Species / export flows | Medium |
| ✅ Web Push | Settings (notifications) | Medium |
| ✅ Public gallery (opt-in) | CONFIGURATION → Gallery | High |
| ✅ Migration calendar | Overview / patterns | High |
| ✅ Region comparison (eBird) | Overview card | High |
| ✅ Sun/moon card on weather | Overview / weather | Low |
| ✅ Video prev/next (same UTC day) | Video details + GET /api/ui/videos/:id/neighbors (#82) |
Low |
Note: For new ideas use Discussions or an Issue per the triage table above.
UX improvements (shipped)
| Item | Status |
|---|---|
| Activity month picker | Shipped (v0.1.8) |
| Unknowns empty state | Shipped |
| Unknowns time-of-day filter | Shipped (v0.1.9) |
Work order: finish in-flight work, then operator testing
Agreement: first complete the agreed slice of work (open issues in the current wave / BirdLense Hub — Roadmap milestone: PR merged, issue closed, make deploy if needed, CI green). Then the operator runs manual testing on the live hub and files feedback as new issues (or flags regressions on an existing issue) — without growing the same wave in parallel.
Backlog vs acceptance: rows in New ideas without ✅ are future queue; only items explicitly in progress on the board count toward “ready for acceptance”. The detection consilium (item 17) runs after the current wave stabilizes unless the board decides otherwise.
Tech debt queue (simple → complex)
Execution lives in GitHub issues and the BirdLense Hub — Roadmap board; this section is a pointer only.
- Navigator: #220. Sub-issues (board hierarchy): #198, #201, #221 · #222 · #223 · #224 · #225. Re-link:
bash scripts/github-issue-link-subissues.sh 220 198 201 221 222 223 224 225. RU: ROADMAP.ru.md (wave D). Not this wave: #164, #167.
Near-term priorities (public)
| Priority | Focus |
|---|---|
| Community | Discussions, good first issue triage, docs feedback |
| Quality | CI on PRs (UI build + MkDocs --strict), Dependabot / dependency hygiene |
| Docs | VERSION aligned with mkdocs.yml, app/ui/package.json, and app/web/openapi.yaml (scripts/check-docs-version.py); interactive OpenAPI (Redoc) on the doc site |
| Releases | Tags + GitHub Release → Docker semver image + Pages deploy |
The shipped archive above is historical only. Active work is the consilium issues and future candidates; always cross-check FEATURES.