Skip to main content

Roadmap

What is being built, by release. Every item is a GitHub issue — this page is generated from the tracker, so it cannot describe work that is not tracked.

v0.5.0

Deployment and release hardeningReady to ship

Release tooling, deployment shapes, and the security and correctness work that came out of a full rehearsal.

220/220
220 issues
ASR Engines
  • #455 fix(transcription): storage.py overwrites MediaFile.duration with 0.0, and speaker sets are non-deterministic
  • #456 fix(transcription): garbage-word cleanup edits text but not words, and rewrites whitespace on every segment
  • #470 ASR providers: real defects found writing #445 test coverage (punctuation loss, retry never fires, timeout bool discarded, wrong response_format)
  • #584 Lite mode: cloud-ASR speaker embeddings silently never complete (GPU-only queue, no lite worker)
Document Ingestion
  • #362 feat: Document ingestion & knowledge base — parse, index, and chat over documents alongside transcripts
Frontend & UI
  • #174 Refactor: Split oversized frontend components (FileDetail, SettingsModal, TranscriptDisplay, Speakers)
  • #298 bug(upload): single-file limit is 15 GB but multi-file drop rejects at 2 GB
  • #301 bug(frontend): MediaFile status union is missing queued, downloading, and quarantined
  • #302 bug(frontend): audioExtractionService hashes on the main thread — tab freeze / OOM on large video
  • #326 i18n: ~65 remaining bypasses in the service/store layer + tag-shape contract disagreement
  • #327 upload: no browser-side presigned multipart or resume for multi-GB files (A2.9 remainder)
  • #335 bug(file-detail): tag changes never propagate — TagsSection says "re-emit to parent" but never dispatches
  • #338 cleanup: `reactiveFile` is a write-only store — 13 writes, zero readers
  • #342 bug(upload): client-side SHA-256 silently skips duplicate detection above ~4 GB
  • #352 bug(file-detail): renaming a speaker does not update the transcript until a full page reload
  • #376 Frontend dead-code cleanup: knip audit findings
  • #452 Responsive: nav overflows at 1280px and clips the user menu; 1280 is an untested breakpoint
  • #475 Test suite: frontend statement coverage is 14.27%; core service/store/api logic largely untested
  • #489 Watch sources: per-file management UI is entirely unbuilt despite full backend/API support
  • #490 Watch sources: per-source email-notification linking UI is entirely unbuilt despite full backend/API support
  • #527 Gallery: virtualized rendering and real thumbnails
  • #578 task(backend): confirm whether speaker rename/verify still live-updates other connected clients via WebSocket
  • #583 ShareCollectionModal hardcodes canManage=true regardless of collection ownership
  • #585 fix(frontend): file detail page canEdit fails open on missing/null my_permission
  • #645 Waveform seek can stall ~10-30s on a fresh page load before media metadata is ready
LLM Providers
  • #596 fix(llm-provider): Bedrock LLM provider is implemented but unreachable — no schema/UI wiring
Native Diarizer
  • #193 [FEATURE] Improve diarization at boundaries
  • #299 bug(diarization): _normalize_speaker_label raises TypeError on every call (object.__new__ on an abstract class)
  • #482 speaker_processor.mark_overlapping_segments loses overlap data when a segment spans two overlap regions
  • #483 Duplicate normalize_speaker_label implementation in speaker_processor.py diverges from the canonical version
  • #520 diarization follow-ups that need a GPU window: speakrs boundary fixture twin + sidecar EP smoke test
  • #571 task(asr): migrate CPU-lite + speaker-embedding path off PyTorch/PyAnnote onto native diar-native
  • #579 diar-native: WAV write failure hard-fails the pipeline instead of degrading to PyAnnote fallback
  • #621 fix(frontend): local diarization settings/About/reprocess text still credit PyAnnote as primary, not diar-native
Platform & Operations
  • #21 [ENHANCEMENT] Implement Comprehensive Testing and Enable CI/CD Pipeline
  • #26 [FEATURE] Automatic Bucket Processing with User Access Controls
  • #123 E2E Test Expansion: Gallery, Upload, Settings, Transcription, Search & CI/CD
  • #189 [BUG] Quick Installation documenation incorrect
  • #190 [FEATURE] auto-ingest a file share or support api uploads
  • #234 Testing follow-ups: coverage ratchet, responsive E2E, deferred dep majors
  • #241 Modernize UUID columns: native pg uuid type + generation strategy review
  • #242 Backup extension: MinIO media mirror (OpenSearch snapshots DONE in #239)
  • #243 Back up encryption keys / .env alongside the database (or backups are unrecoverable)
  • #244 Surface scheduled-backup failures (Prometheus metric + notification)
  • #245 Operational: re-ingest the media corpus in place after #239 merges (GPU 1)
  • #272 Latent always-False FileStatus string comparisons (found by the py312 codemod audit)
  • #293 bug(watch-sources): SMB download size-mismatch check is unreachable — truncated downloads import silently
  • #294 bug(watch-sources): watch.fs_events_enabled is a no-op — no watchdog Observer exists
  • #295 bug(watch-sources): watch.max_concurrent_imports is a per-scan slice cap, not concurrency
  • #297 bug(tests): pytest.mark.gpu is unregistered and silently ungated — GPU tests run in fast CI, integration gate under-covers
  • #303 docs(release-tests): README claims hard isolation, but the scripts use live ports and stock container names
  • #320 perf/correctness: `async def` functions that never await block the event loop (OpenSearchSummaryService + 78 endpoint handlers)
  • #325 test: `@pytest.mark.unit` test downloads a HuggingFace model and randomly reddens CI
  • #334 bug(sse): bulk-export stream can hang forever — check-then-subscribe lost-wakeup race
  • #343 bug(opentr.sh): --port-offset does not offset — Compose appends port lists
  • #347 bug(opentr.sh): --fresh cannot isolate the ldap/smb/monitoring test overlays
  • #355 [BUG] Flower container always reports as unhealthy
  • #389 Flaky tests: cross-worker Postgres deadlocks + order-dependent failure in migration/settings tests
  • #397 test(routes): /api/auth/me/certificate has no frontend caller and no allow-list entry
  • #398 Pre-existing defects surfaced by the release-engineering gates (2 failing tests + 4 schema findings)
  • #399 fix(bench): engine/status gate on the dev stack's container names — the bench overlay renames everything to otbench-*
  • #407 Unattended install aborts at the final step: set -e + pipefail on an absent optional .env key
  • #408 Fresh-install release scenario is not repeatable: it reuses the previous run's database
  • #409 Unattended install never persists HUGGINGFACE_TOKEN: every transcription fails
  • #410 v0.5.0 BREAKING: existing v0.4.x deployments without REDIS_PASSWORD will fail to start after upgrade
  • #411 Every production container reports its version as "unknown": compose blanks the baked APP_VERSION
  • #412 rehearse stage can never reach Scenario B: Scenario A leaves its stack running
  • #413 SECURITY: the release scan gate is fail-open — finding CRITICAL CVEs makes it PASS
  • #414 SECURITY: the release scan gate scans the PREVIOUS release, not the release candidate
  • #423 Upgrade Docusaurus 3.9.2 → 3.10.2 (MDX v3 content migration required)
  • #431 Test suite: 81% of wall clock is one serialized worker + 8 lock barriers; 232 security tests never run; 113 modules untested
  • #434 pre-commit stashes the WHOLE tree on every run — it has destroyed in-flight work twice
  • #440 DB sessions held across slow work hang Alembic and wedge the database
  • #445 Test suite: 41% of backend modules have no test reference; four authz decorators untested
  • #446 Mutation testing: ~275 of 636 survivors are real gaps, not log noise — triage the top findings
  • #447 Visual regression: all 8 baselines failing
  • #450 auth_decorators.py + transcription_service.py are dead code (~650 LOC); require_verified_user doesn't verify
  • #451 Visual regression: all 8 baselines depend on live mutable dev data and cannot be honestly refreshed
  • #454 Test isolation: tests/unit fixtures vanish when a tests/*.py file is collected in the same run
  • #457 fix(recovery): the request cap stops bounding requests exactly when fetches are failing
  • #458 fix(gpu): a healthy GPU reports 'No GPU Available', and GPU_SCALE_DEFAULT_WORKER=true is silently False
  • #459 mutation --verify: class-method mutants always UNVERIFIABLE (dedented diff matched against un-dedented source)
  • #474 Test suite: 57 backend modules have zero test reference after #445/#470
  • #485 Celery apply_async() intermittently dispatches to the default AMQP broker instead of the configured Redis one — every admin "Run now" action 500s
  • #486 test_speaker_metadata.py fails intermittently under xdist parallelism (passes clean standalone)
  • #487 Golden-fixture drift: test_boundary_regression word-count mismatch (2282 ref vs 2251 hyp) — real accuracy drift or stale fixture?
  • #491 NLTK/offline: corpora fetched at runtime, airgap coverage incomplete
  • #492 requirements.txt pins almost nothing: venv and container diverged by 120 packages (18 major)
  • #493 Integration phase: 95 tests take >30 min, cannot pass on 12GB GPU, and has no per-test timeout
  • #500 Dockerfile.blackwell: huggingface_hub==0.23.5 downgrade makes `import transformers` fail outright
  • #522 Ingest real media into dev by pulling from the NAS store (first true ASR + diarization run)
  • #528 BUG: --no-bindmount can serve a stale image, silently invalidating measurements
  • #529 Final merge gate for feat/rag-transcript-intelligence: full suite, benchmarks, E2E
  • #538 opentr.sh: load the diar-native overlay so dev runs the primary diarization engine, not its fallback
  • #539 Audit every .env / .env.example variable: read-by-what, accurate, useful — and keep the template in sync
  • #541 E2E: a speaker test persists prediction state onto a real profile (data-hygiene violation)
  • #545 refactor(backend): audit duplicate public function names — two normalize_language implementations disagree
  • #553 bug(opentr.sh): a plain 'start dev' has no port pre-flight, so a collision half-starts the stack
  • #567 bug(config): five defects found by the .env audit — non-functional GPU clustering device, 3 phantom ASR aliases, unimplemented FedRAMP AC-2
  • #568 bug(testing): DIARIZATION_VRAM_BUDGET_MB perf-gate test asserts a propagation mechanism that doesn't exist
  • #577 task(testing): diarization GPU integration tests unrunnable via either documented path (venv torchaudio drift + benchmark container missing test deps)
  • #580 fix-shared-volume-perms.sh: default chown GID (1000) doesn't match the image's appuser GID (999)
  • #586 test(diarization): pyannote.ai cloud diarization provider has no direct test coverage
  • #590 refactor(scripts): replace hand-rolled bash .env parsing + ad-hoc smoke scripts with python-dotenv + pytest
  • #591 chore(docker): promote compose-only env vars to .env.example, fix TEMP_DIR name collision
  • #592 Upgrade rehearsal proves the happy path; there's no failure-recovery doc or in-script guidance for a failed ./opentranscribe.sh update
  • #597 CI: Release Validation dry-run fails on missing NAS mount, not a real deployment defect
  • #598 Release rehearsal matrix has no coverage for opentr.sh backup/restore or opentranscribe.sh update --rollback
  • #599 P0: opentr.sh restore silently fails to restore data — exits 0, reports success, changes nothing
  • #600 P0: scheduled backup_service.py produces -Fc custom-format dumps with NO restore path anywhere in the repo
  • #601 cleanup-test-users.py --execute (real DELETE FROM "user") has zero test coverage
  • #602 fix-model-permissions.sh / fix-shared-volume-perms.sh have zero test coverage (chown on real data volumes)
  • #604 backup.encrypt (scheduled/S3 backup gpg encryption) fails in production — gnupg not installed in backend image
  • #607 UserLLMSettings.is_active is vestigial (always defaults True, never reflects the real active config) — silently defeats the e2e ensure_llm_provider fixture
  • #608 docker-compose.llm-test.yml's default Gemma-4-E4B-AWQ config does not fit a 12GB GPU even with the entire card free — full-test-matrix.md's <=0.45 guidance is insufficient
  • #609 Flower /api/workers never shows threads-pool Celery workers (gpu-scaled@*, gpu-transcription@*) — gpu-scale-smoke.sh cannot pass
  • #610 opentr.sh restore silently lets the running (newer) app auto-migrate a just-restored older backup forward — blocks the rollback rehearsal's phase 15-17 chain
  • #612 fix(testing): search-quality suite fails 2 unrelated checks on a brand-new --fresh deployment (OpenSearch ML model not yet active)
  • #613 opentr.sh missing from release-manifest.txt while docs instruct operators to run it for restore/rollback
  • #614 MINIO_KMS_SECRET_KEY placeholder in .env.example isn't a format MinIO accepts, blocks a truly-fresh cp .env.example .env boot
  • #616 fix(docker): docker-compose.backup.yml is not shipped, so the in-app scheduled/S3 backup has no mounted destination in production
  • #617 Release rehearsal: dbs_diff_fingerprints() unguarded under set -e silently truncates phases 15-18
  • #618 Release rehearsal: unguarded curl to frontend under set -e silently kills phase 16→17→18 (same class as #617)
  • #619 fix(release-tests): test-upgrade.sh F-4 (media_file digest) and phase-06b backup-content-diff race async DB writes — same class as #617's Layer 1
  • #620 fix(security,testing): post-rehearsal adversarial review findings (8 items, 1 HIGH)
  • #622 fix(backend): detect_speaker_attributes and redaction_detect_task have no Task DB record
  • #629 task(testing): automatic, signature-scoped cleanup of orphaned e2e/test data across ALL leak classes
  • #630 task(testing): run-dev-tests.sh should dynamically start/stop auth-overlay containers (Keycloak, LDAP, etc.) like it does mock-llm
  • #640 setup-opentranscribe.sh doesn't read release-manifest.txt — fresh installs never get docker-compose.blackwell.yml or docker-compose.backup.yml despite the manifest's own header claiming it's a consumer
RAG & Chat Quality
  • #52 Feature: AI Interactive Chat with RAG System for Selected Transcripts
  • #78 Feature: Admin-Controlled Prompt Sharing System
  • #136 [Tip] Example AI summary for Q&A panel
  • #359 chat: per-conversation max_tokens and top_p
  • #360 chat: projects with pinned scope and project-level prompts
  • #383 feat(chat): corpus-scale RAG — summary tier, query routing, aggregation, model-tier parity, and a real eval harness
  • #384 fix(chat): sources frame is sent before the excerpt budget is known — UI can show citations the model never saw
  • #385 fix(chat): tag-scoped chat silently excludes shared files (tag scope is owner-only, collection scope is not)
  • #386 fix(chat): history_max_turns counts pairs in one place and messages in another, halving conversation depth
  • #387 fix(chat): first excerpt is always emitted even when it alone exceeds the prompt budget
  • #403 feat(rag): master orchestrator — ordered end-to-end implementation of corpus-scale RAG, retrieval tuning, and documents (#383 → #363 → #362)
  • #438 fix(chat): an unscoped conversation searches nothing — file_uuids defaults to [] (match nothing), not None (all accessible)
  • #439 fix(chat): Gemma reasoning and a raw <channel|> control token leak into the user-visible answer
  • #448 Backlog: multilingual RAG/chat — CJK transcripts produce one un-chunked blob (English-only is the current scope)
  • #453 Multilingual RAG and chat: four independent stages, none of them a setting
  • #461 RAG retrieval quality: what is measured, what is not, and what to do next
  • #463 eval: measure whether chat answers are actually useful — QMSum reference answers are already on disk and unused
  • #465 AI summaries are displayed and exported completely unmasked, ignoring the user's redaction policy
  • #495 RAG eval harness: synthetic corpus injection indexes no chunks on re-injection (test xfailed)
  • #514 Live query-trace panel: an animated, Redis-pushed execution tree for search and RAG
  • #515 Umbrella: RAG/chat/search/document-ingest completion — status, plan corrections, and open decisions
  • #517 eval: scope coverage — the metric no framework measures, and the bug it hides
  • #518 eval: calibrate the LLM judge with Cohen's Kappa before tuning anything on it
  • #519 eval: acceptance suite for the four real query shapes, over AMI ground truth
  • #521 eval: add ELITR-Bench (CC-BY-4.0) — first benchmark that tests speaker attribution directly
  • #524 RAG: the speaker axis silently disables itself at corpus scale (roster cap declines wholesale)
  • #525 RAG: widening the candidate pool changes nothing — ranking keeps selecting content-free fragments
  • #530 RAG: calibrate the answer judge with Cohen's Kappa (gates every quality claim)
  • #531 RAG: shipped 48/12/4 retrieval budget starves the chat — 2x recall available
  • #533 LLM settings: discover a model's context window instead of defaulting to 8192
  • #534 RAG: validate the budget finding on a second corpus (ELITR-Bench) before changing defaults
  • #535 RAG: standing acceptance suite over the four query shapes
  • #536 chat: base rules leak prompt-internal block vocabulary into answers when the block is absent
  • #589 bug(services): group_batch_by_topics miscounts a collection collision as a creation
  • #595 test(release-tests): lite-mode rehearsal chat-summary text comes back empty despite citations succeeding
  • #611 Lite-mode rehearsal: chat SSE stream sends the model's real answer inside an event: error frame's 'code' field
Search Infrastructure
  • #363 search: measure RRF vs score-based hybrid fusion, and record the speaker-turn chunking decision
  • #400 fix(search): re-running search indexing never deletes existing chunks — stale tail chunks survive a shorter re-chunk
  • #401 fix(search): ingest pipeline recreation compares only model_id — a field_map change is silently ignored on upgrade
  • #402 chore(docs): four doc-drift fixes found during the #383/#363 second-opinion review
  • #405 fix(search): speaker and title renames never propagate to transcript_chunks — chat speaker scope, search facets, and citations serve stale names until a full reindex
  • #432 fix(search): six more display_name writers still leave stale speaker names in transcript_chunks
  • #433 fix: ORDER BY start_time is not a total order — re-indexing the same transcript yields different chunks
  • #435 fix(search): chunk-prune count gate reads the searcher, so a re-index inside the refresh window leaks orphans permanently
  • #436 fix(search): indexing workers have no nltk_data mount — every production chunk was cut by the regex fallback
  • #437 fix(search): switching the embedding model silently leaves a mixed-vector index, and embedding_model records the mode not the model
  • #449 Chunk boundaries depend on whether NLTK punkt loaded — and on a 5-minute global cooldown
  • #501 Bulk indexing fails intermittently: ML Commons circuit breaker false-trips on young-gen garbage
  • #502 Offline embedding-model registration is broken on OpenSearch 3.4 (400 'model config is null')
  • #503 Verify at setup that the selected embedding model actually works, and size heap per machine
  • #504 Embedding model registry offered paraphrase-multilingual-mpnet-base-v2, which OpenSearch does not provide
  • #540 OpenSearch startup maintenance: probe the kNN plane and self-heal — vector corruption survives restarts silently
  • #542 Dead ANN branch in opensearch_service/transcripts.py::search_transcripts would 400 if ever called
  • #606 Semantic search fails to find the obvious gold file for 'space exploration' query, surfaces both anti-gold files instead
  • #625 fix(search): neural-search bootstrap is one-shot with no retry, can permanently lose model deployment on a cold OpenSearch boot
  • #626 task(search): operator-triggered re-embed for files indexed during a neural-search degraded window
  • #638 Offline model registration (file://) is dead in every deployment mode: missing opensearch-ml volume mount + missing config.json
Security & Compliance
  • #188 [BUG] LDAP cn not parsed correctly
  • #262 Post-0.5.0 hardening follow-ups from the cloud-seams security review
  • #284 Improvements & Security Review
  • #296 docs(redaction): redaction_task.py docstring claims unconditional detection — dispatch is actually gated
  • #300 bug(asr): AWS access_key_id is dropped when building the provider for a job (test-connection passes, transcription doesn't)
  • #324 security: six remaining fail-open paths deferred from #284 Phase 3B
  • #353 [BUG] Generic OIDC / Authentik does not work because OpenTranscribe hardcodes Keycloak realm URLs
  • #354 [FEATURE] Disable self-registration via environment variable
  • #441 JWT algorithm decision is duplicated 3x with different gates; issuers and verifiers disagree
  • #442 GDPR Art. 17: no erasure ledger, legal-hold data never re-erased, backup restore resurrects subjects
  • #443 Audit log: split user_id into actor and target (schema change, not a convention)
  • #444 chat_completion — the production LLM path — has no SSRF validation at all
  • #471 Replace gender-guesser (GPLv3) with a permissively-licensed alternative
  • #473 Compile a minimal, license-confirmed FFmpeg.wasm core (replace generic @ffmpeg/core CDN fetch)
  • #484 directory_sync (LDAP deprovisioning sweep) has no admin settings endpoint — unreachable in any real deployment
  • #497 Cross-tenant authorization gap: update_comment and delete_comment run no tenant check
  • #498 Five PKI revocation settings are writable in the Settings UI and read by nothing
  • #499 PII masking misses names spaCy labels ORGANIZATION, which the default policy excludes
  • #513 perf(redaction): ONNX-convert toxic-bert and the search embedding model (and why Presidio should stay in Python)
  • #573 docs(compliance): FIPS_140_3_COMPLIANCE.md claims 'FIPS 140-3 compliant' but only implements FIPS-approved algorithms, not a validated module
  • #575 docs(compliance): password policy (forced expiry + composition rules) contradicts current NIST SP 800-63B Rev. 4, not FedRAMP IA-5 best practice
  • #582 SCIM PUT does not implement RFC 7644 replace semantics
  • #587 test(services): AutoLabelService tenancy-scoping and per-user cache paths are untested
  • #588 fix(auth): viewer-permission users can reprocess/summarize shared files via API
  • #593 PKI E2E admin-cert fixture collides with super_admin email-link protection
  • #594 ASR UserASRSettings.base_url is validated and persisted but never consumed — wiring it needs an SSRF guard first
  • #615 PKI_TRUSTED_PROXIES default CIDR doesn't cover the full range Docker can assign to a compose network (breaks mTLS header trust under --fresh)
  • #623 fix(frontend): PKI/proxy trusted-CIDR admin UI still suggests the now-fixed vulnerable range
  • #632 Session accumulation: refresh_token rows for one user hit 272x the configured max_concurrent_sessions limit
  • #633 refresh_token rows accumulate unbounded on admin@example.com (5,504+ observed)
Speaker Intelligence
  • #512 feat(speakers): cross-file speaker clustering — ANN index over speaker embeddings + batch re-resolution
  • #543 SpeakerProfile.predicted_gender is written but never read — confirming a gender on a member-less profile is silently invisible
  • #603 Speaker confirm-gender/merge don't propagate to other open tabs (cosmetic, self-correcting on reload)
  • #605 Live speaker chunk-index label drifts from canonical_speaker_label() resolver (speaker_id=74070)

v0.6.0

Answer quality and interface polishIn progress

Make what already ships correct — grounded answers, searchable summaries, an interface pass, and the fixes that affect running deployments today.

0/30
30 issues
Frontend & UI
  • #569 feat(frontend): wire persistent download notifications into the live notification bell
  • #570 feat(admin): expose locked-account management (view/reset) in the admin UI
  • #576 feat(admin): quarantine/takedown has no UI — admin must curl 3 backend-only endpoints
  • #649 Audit other interactive UI paths for the same premature-interaction timing bug class as #645
  • #682 fix(frontend): UI bug backlog for the v0.6.0 UI refresh (filters, modal styling, button states)
LLM Providers
  • #644 Admin LLM provider setup: surface discoverable local base URLs instead of requiring manual Docker hostname entry
Native Diarizer
  • #655 bug(docker): diar-native sidecar is unwired in gpu-scale, gpu-split, lite, offline, Windows, --fresh and CPU-only topologies
  • #662 bug(config): .env.example ships DIAR_NATIVE_GPU=0, restoring the bare-device-0 pin the compose comment exists to prevent
  • #665 fix(gpu): overlap-diarization gate keys off the configured backend, not sidecar reachability — transcriber is never released on the PyAnnote fallback path
  • #671 docs(backend): transcription/ and services/diarization/ CLAUDE.md still describe PyAnnote as the engine
  • #672 bug(config): PYANNOTE_MODEL means two different things, the admin panel misreports the diarizer, and four diarizer symbols are dead
Platform & Operations
  • #631 Celery prefork pool death spiral: 10h46m of forked children failing to signal UP, root cause unknown
  • #680 bug(docker): the published arm64 backend image is not equivalent to amd64 — 765 MB vs 4,454 MB, dependency layer 8.4x smaller
  • #681 bug(ci-cd): an unscannable component yields "All security scans completed successfully!" — docs is already in this state
  • #683 [BUG] Can't install due to "❌ Failed to download release-manifest.txt from v0.4.1" - 404: Not Found
RAG & Chat Quality
  • #462 feat(search): make AI summaries searchable and citable in the search page
  • #464 feat(rag-chat): use LLM summaries as the map output when an LLM is configured (tiered tree_summarize)
  • #506 task(rag-chat): measure dropping the stemmed BM25 leg for non-English queries (deferred from #453)
  • #523 task(rag-chat): short speaker turns become content-free chunks — route speaker questions, expand context at read time
  • #526 task(rag-chat): context expansion decouples citations from their source chunk (snippet longer than the chunk it cites)
  • #532 task(rag-chat): retrieval offers 99% of scope but the answer cites 75% — synthesis, not retrieval
Search Infrastructure
  • #627 fix(search): admin "Reindex all" only re-indexes the admin's own files, not the whole corpus
  • #658 bug(operations): speaker voiceprints live only in OpenSearch and no backup covers them
  • #666 fix(search): a transcript text edit never reindexes OpenSearch — search, RAG retrieval and citations serve pre-edit text indefinitely
Security & Compliance
  • #664 fix(security): retention sweep and purge_media_file have no legal_hold guard — a legal-held file can be permanently deleted
  • #668 security(deploy): nginx/reverse-proxy hardening — trusted-proxy rate-limit collapse, pre-auth body buffering, missing robots.txt
  • #673 fix(redaction): export_locked is enforced only for subtitles — the admin forced-redacted-export policy is bypassable via every other export format
  • #676 security(api): LLM connection-test and model-discovery handlers make user-supplied outbound requests with no rate limit
Speaker Intelligence
  • #674 fix(speakers): auto-accept threshold is passed as OpenSearch min_score in cosinesimil space — the effective gate is raw cosine 0.50, not 0.75
  • #675 fix(search): speaker profile rename never propagates to transcript_chunks — the one rename path that skips dispatch_speaker_rename

v0.7.0

Documents, speakers, and providersUp next

Widen the library beyond audio, deepen cross-file speaker identity, and add provider breadth.

0/22
22 issues
Document Ingestion
  • #516 feat(documents): unified gallery with type filter, uniform status, recovery and takedown parity
  • #546 fix(documents): Document.file_hash is written by both ingest paths and read by neither
  • #547 fix(documents): watch-imported documents are unrepresentable in the watch-source API (no document_uuid; two statuses missing from the enums)
  • #552 task(documents): re-land the document-ingestion vertical from feat/doc-ingestion for v0.6.0
Frontend & UI
  • #20 feat(analytics): add analytics dashboard to gallery view
  • #564 feat(export): Markdown-file export format
LLM Providers
  • #378 feat(llm): Add Tinfoil confidential-computing LLM provider
  • #379 feat(llm): Add Google Gemini as a first-class LLM provider
  • #380 feat(llm): Add Groq as a first-class LLM provider (low-latency inference)
  • #382 feat(llm): Add GCP Vertex AI as an SDK-based enterprise LLM provider (Bedrock-style)
Native Diarizer
  • #661 perf(pipeline): collapse the audio handoff — four decodes and ~2.1 GB of one signal per job
  • #679 Adopt diar-native 0.3.0: self-provisioning models, CPU/GPU routing, /readyz, and structured logs
Platform & Operations
  • #369 perf(gpu): calibrate transcriber eviction + concurrency from measurement, not magic numbers (limited-VRAM cards)
  • #468 task(governance): set up Contributor License Agreement (CLA) enforcement
  • #566 task(config): move UI-worthy env vars into the admin UI, then drop them from .env.example
Public Demo
  • #628 feat(deploy): public read-only demo deployment (Immich-style inert demo instance)
  • #667 build(release): publish the CPU-only lite image as a multi-arch (amd64 + arm64) release artifact
RAG & Chat Quality
  • #562 feat(llm): custom note templates per meeting type (standup/1:1/interview)
Search Infrastructure
  • #46 feat(transcript): transcript version control and change tracking
Security & Compliance
  • #559 security(dependencies): evaluate replacing Perl exiftool (16 of 20 CRITICAL CVEs) — ffprobe-only vs exiftool-rs
Speaker Intelligence
  • #550 feat(speakers): Speaker Persona Profiles — corpus-level speech, topic and role profiles grounded in deterministic conversation metrics
  • #624 task(speakers): profile speaker-matching kNN performance at scale + add a decision-parity fixture

v0.8.0

Native diarizationLater

Retire the in-process PyTorch diarizer for the native Rust/ONNX engine, including the voiceprint migration it depends on.

0/10
10 issues
Native Diarizer
  • #572 task(asr): roadmap for removing PyTorch/PyAnnote diarization once native diar-native has parity
  • #639 Diarization backend defaults to native (diar-native sidecar) but the sidecar is never distributed to self-hosted installs — perpetual silent-ish PyAnnote fallback
  • #654 task(models): add a download-models diar-native group — the export four files already claim exists
  • #656 task(asr): sidecar-unavailable retry policy, bounded timeout and status surface before the PyAnnote fallback is removed
  • #657 bug(search): v4 embedding migration loses profile voiceprints and crosses index dimensions mid-run
  • #659 feat(search): a real rollback path for the v3→v4 speaker-index alias swap
  • #660 task(asr): --lite adopts the diar-native CPU execution provider for speaker embeddings
  • #663 docs(legal): add a NOTICE file — the native diarizer's weights are CC-BY-4.0 and still require pyannote attribution
  • #669 task(testing): diarization test + gate coverage survives the PyAnnote removal (several would go green measuring nothing)
  • #670 bug(deploy): upgrading into a mandatory-sidecar release degrades silently instead of refusing

v0.9.0

Meetings and extensibilityLater

Bring meetings in automatically and open the pipeline to external tooling.

0/7
7 issues
Meeting Capture
  • #365 feat(asr): Recall.ai meeting capture — ingest meetings, transcripts, speakers and metadata into the same library
  • #563 feat(calendar): calendar integration (foundational)
  • #565 feat(rag-chat): pre-meeting briefs from calendar + past transcripts
Native Diarizer
  • #511 perf(gpu): build and measure a 4 GB laptop GPU tier for native diarization
Platform & Operations
  • #274 build(docker): Blackwell base image upgrade (nvidia/pytorch 26.x) — needs a torchaudio strategy + hardware validation
  • #561 feat(backend): plugin/post-processing hook architecture for transcription pipeline
RAG & Chat Quality
  • #560 feat(rag-chat): MCP server for transcript/RAG-chat access by external AI agents

v1.0.0

Platform maturityLater

Alternative transcription engines, a desktop application, live transcription, and formal compliance validation.

0/6
6 issues
ASR Engines
  • #48 feat(asr): implement native Apple Silicon transcription with MLX-Whisper or whisper.cpp
  • #69 feat(asr): live transcription with real-time speaker identification
  • #366 feat(asr): NVIDIA NeMo (Parakeet / Canary) as a first-class local transcription engine
Desktop App
  • #283 feat(desktop): cross-platform standalone desktop app (Tauri + SQLite/sqlite-vec + local inference core)
Security & Compliance
  • #98 security(compliance): HIPAA, SOC 2, and GDPR certification requirements
  • #574 task(security): achieve real FIPS 140-3/140-2 module validation (not just approved algorithms) for FedRAMP High/DoD IL4+

Backlog

Not yet scheduledUnscheduled

Tracked and grouped, but not assigned to a release. These move into a version as the work ahead of them lands.

0/1
1 issue
Security & Compliance
  • #415 security(dependencies): accepted risk — 16 CRITICAL perl CVEs via libimage-exiftool-perl, re-check when Debian ships fixes

Releases are ordered by dependency, not scheduled to dates — a later release is blocked on the one before it. Scope moves between releases as work is understood. For the reasoning behind any item, open its issue: that is where the detail lives.