ADR-0206: Navin Enterprise Meeting Intelligence Agent, authorized capture and meeting intelligence above the Control Plane
- Status: proposed (2026-11-05)
- Deciders: Navin Enterprise AI platform team, brief 02 mission (
agent_uses_cases/tel_note_meeting/02_NAVIN_AGENT_MEETING_EQUIVALENT_LEEXI.md) - References: ADR-0176 (UC-00 model whose generic modules are copied), ADR-0177 (rule of the agents: never a second
installation of a shared service), ADR-0173 (telephony platform Asterisk, Kamailio, LiveKit), ADR-0205 (Notes
product, destination of pages and tasks), ADR-0101 (licence policy), product conventions
navin-enterprise-meeting/CONVENTIONS.md, OPA packageeai.meetings(deploy/policies/opa/meetings.rego, testsmeetings_test.rego, keymeetingsofdeploy/policies/opa/data.json), OpenFGA fragmentdeploy/policies/openfga/products/meetings.fga(+meetings.tests.fga.yaml,meetings.tuples.yaml), Manager cardnavin-meeting-agent(navin-manager/agent-templates/navin-meeting-agent.yaml, statusplanneduntil the Service Template is built, never published without an explicit decision of the customer).
Context
Brief 02 asks for a meeting intelligence agent for the teams of one tenant: authorized capture of meetings (video conferencing, in person, telephony), calendar and participants, media processing, transcription, diarization, summaries, decisions and action items, meeting library, sourced questions and answers, clips and sharing, follow ups, CRM synchronization, multi meeting reports and coaching. The functional target is parity with the usages of a Leexi like tool; nothing proprietary is copied: no code, no model, no brand, and no parity is announced until a real test proves it (section 28 of the brief). The product never records without the legal basis and the consent state its mode requires, never bypasses a waiting room or a recording policy of a provider, and every read, search, export, clip, share, live session and background job re-checks permissions server side (sections 7, 19 and 26 of the brief).
Decision
- Separate product
navin-enterprise-meeting/(product idmeeting, sectorcross_industry) with its own Next.js 16- React 19 + MUI 9 frontend (transcript studio, synchronized player, live interface) instead of the shared shell of
ADR-0180; no root
product.manifest.json. FastAPI backendnavin_meeting(hatchling, Python 3.12, same pins as UC-00), PostgreSQL schemameetingwith RLS forced throughmeeting.current_tenant()/meeting.current_project(), rolesnavin_meeting_migrate,navin_meeting_app(no BYPASSRLS) andnavin_meeting_worker, Alembic with named revisions, Redis prefixedmeeting:{instance_id}:.
- React 19 + MUI 9 frontend (transcript studio, synchronized player, live interface) instead of the shared shell of
ADR-0180; no root
- Reuse of the shared services of the Control Plane through the
enterprise_aiSDK, never a second copy: the media store (upload, ClamAV/YARA-X scan, classification, encryption at rest), speech to text (faster-whisper or an OpenAI compatible endpoint through LiteLLM, word timestamps, DLP on transcripts), diarization (pyannote 3.1 when installed and the Hugging Face token of the customer is configured), LiveKit rooms and the realtime voice protocol (tokens checked server side, consent rows), the connector broker (short lived credentials for Google, Microsoft Graph, Zoom, Webex, CRM and task tools, refresh tokens in OpenBao), the channels of the tenant (email, chat) for follow ups, LiteLLM for the LLM and embeddings, Qdrant/Cognee for the semantic index, the Notes API as destination of pages and tasks. Telephony recordings are imported by reference fromclient.telephony, never recorded a second time. Only the pure VAD logic (Silero ONNX, MIT) is embedded in the worker, which must run without the Control Plane package; ffmpeg/ffprobe are system binaries called as processes, never linked nor bundled. - Honest provider matrix (section 8 of the conventions), exposed by the API and the UI with its status
planned|implemented|tested|partial|blockedand its reason:livekit(native bot participant, one track per participant hence verified speaker attribution) andin_person(browser capture) aim attested;jitsiispartial(no headless participant without a browser, Jibri import when configured);google_meet,teams,zoomandwebexarepartialfor the import of cloud recordings after the meeting andblockedfor the live bot (no approved bot framework delivered);telephonyistestedwith a fake. A denial by the provider (lobby, locked room, policy) is a typed error and aFAILEDattempt with its reason. - Consent modes carried by the instance and decided by OPA before any recording:
explicit_all(every known participant granted),host_declares(ahost_declaredevent logged),announce_only(anannouncedevent logged); denied when the adapter reportsrecording_method = none, denied under legal hold, consent log, logged pause and resume, "recording on" indication in the UI. - Two layer authorization through the Control Plane: OpenFGA for relations (
meeting_instance,meeting_library,meeting,meeting_clip,meeting_report,meeting_template; the backend only checks thecan_*relations;can_export = can_view but not guest;can_record = host or owner; theviewer: user:*of a clip is written only by the sharing service) and OPAeai.meetingsfor the decisions above the relations: recording start (consent, method, legal hold), auto join (external event denied without a rule), external and link sharing (domain, classification, guest), export (legal hold for media, guest, format), clips, CRM write (approval, allowed connector), follow up (approval and checked recipients), task assignment to an external participant (always denied), retranscription and permanent deletion (legal hold, retention), retention change (roles), AI indexing (restricteddenied unless the instance allows it,secretalways denied), individual scorecard (sales manager or the person scored). Fail closed, sorted reasons, every decision audited. - Evidence based AI: every summary, decision, action item, answer and score cites the transcript segments it comes from; a guessed speaker name is never shown as verified; the model neither decides nor executes: CRM writes, task sync and email sending are proposals approved by a human and announced only after the confirmation of the destination API; transcript text is untrusted data (prompt injection) and is never logged.
- Legal hold and retention per tenant, project and type: a legal hold freezes recording, retranscription, clips, media
export and permanent deletion; the semantic index is fed only after the ACL snapshot is taken and never for
restrictedmeetings without the authorization of the instance. - Manager integration through six components
runtime, migrate, backend, worker, live, web(dedicatedstrategy, servicenavin-meeting-agent), development ports web 3490, API 8490, worker health 8491, live 8492, Redis 6410. The registry card staysplannedthenprepared/published: false; artifacts arependinguntil really built.
Consequences
- The product depends on the availability and quotas of the multimodal, realtime, connectors and channels domains of the Control Plane; in exchange it hosts no STT model, no diarization, no connector secret, and benefits from the same controls (antivirus, DLP, audit, kill switch).
- The provider matrix shows
partialandblockedstatuses: parity with a universal bot is not promised; importing cloud recordings after the meeting is the realistic path for Google Meet, Teams, Zoom and Webex. - Every new sensitive action goes through a
can_*relation and aneai.meetingsdecision; an action missing from the policy is refused (unknown_action). - The
liveprocess is one more component to supervise (health, metrics, WebSocket sessions); the consistency of PostgreSQL + media store is verified by the restore test. - The card stays absent from the catalog until an explicit validation is given.
Security
- Identity and delegation: the bot and the workers carry a workload identity and the delegation context of the user, never a raw password; LiveKit tokens are checked server side, development defaults are refused in production; identity never comes from the browser.
- Threats of section 26 of the brief covered by denial tests: malicious invitation and unauthorized auto join (OPA rule
meetings.join.auto), spoofed webhook (verification by the connector broker), link leak (meetings.share.linkdenied for classified content, short signed URLs), malicious media payload (media store scan), prompt injection in the transcript (untrusted content, tools checked against the permissions of the caller), cross tenant retrieval (RLS and ACL filters of the index), synthetic speaker attribution (never shown as verified), unauthorized CRM write (mandatory approval). - Append only audit of every decision and side effect; DLP
maskon exports; legal hold and retention enforced by the policy and by the deletion jobs.
Alternatives considered
- STT and diarization models embedded in the product: rejected (ADR-0177); the Control Plane already provides them with DLP, quotas and audit, and a second copy of the weights would double the maintenance and licence surface.
- Universal bot joining any video conference through a headless browser: rejected; it bypasses the approved frameworks
of the providers and their recording policies; the product delivers a native LiveKit bot, cloud recording import and
browser capture, and shows
blockedwhere no approved framework exists. - Grafana, Loki and Tempo for observability: refused, AGPL licence (ADR-0101); Prometheus, Alloy, OpenSearch, Jaeger and Opik are used.
- A second semantic index owned by the product: rejected, Qdrant/Cognee through the Control Plane stay the only source with ACL filters.
- Shared frontend shell of ADR-0180: rejected, a transcript studio synchronized with the media cannot be described by a shell driven manifest.
Open questions
- Zoom Meeting SDK app: required for a live Zoom bot, not delivered; decision of the customer on publishing an app in their Zoom account.
- Teams bot registration (Azure Bot Service, Graph application permissions): out of scope until the tenant grants the permissions; only the import of Graph recordings and transcripts is planned.
- Gated pyannote weights: the customer must accept them on their Hugging Face account and configure
EAI_HF_TOKENon the Control Plane; without it diarization is unavailable and the per track LiveKit attribution stays the only verified attribution. - Jibri for Jitsi: capture is possible only if the customer runs Jibri and exposes the recordings directory or the finalize webhook; manual upload otherwise.
Links
- Brief:
agent_uses_cases/tel_note_meeting/02_NAVIN_AGENT_MEETING_EQUIVALENT_LEEXI.md(sections 2, 7, 19, 26) - Conventions:
navin-enterprise-meeting/CONVENTIONS.md - Policies:
deploy/policies/openfga/products/meetings.fga,deploy/policies/opa/meetings.rego - Card:
navin-manager/agent-templates/navin-meeting-agent.yaml - French version:
docs/architecture/ADRs/ADR-0206-navin-enterprise-meeting-agent.md