v0.12.23

Vexa-ai/vexav0.12.23Aug 20, 2026by DmitriyG228

Upgrading?

AI Summary

This release introduces calendar auto-join discipline and Teams CSRC transcription, replacing Redis with Valkey and enforcing one-bot-per-meeting guarantees.

Key Highlights

  • Calendar auto-join discipline (dispatch 2 min early, wait 15 min).
  • Teams CSRC transcription routes audio into per-speaker windows.
  • One bot per meeting guarantee enforced.
  • API key scope enforcement on bot lifecycle.
  • Redis replaced with Valkey 8.1.9.

Breaking Changes

  • Admin service refuses to start without a unique index (schema migration required).
  • Redis replaced with Valkey (custom images need update).
  • Declared `api.v1` surface not frozen for routes added since 0.12.18.

New Features

  • Calendar auto-join discipline with retry logic.
  • Teams CSRC transcription.
  • Multiple calendar feeds support.
  • Per-bot scope enforcement.
  • Valkey 8.1.9 base.

Full Release Notes

# v0.12.23 — Calendar auto-join discipline, and Teams CSRC transcription

Calendar-dispatched bots now follow a fixed, observable contract: dispatch at
start−2 min, wait up to 15 min in the lobby, retry genuine failures once per bounded
backoff inside the occurrence window, never re-arm a served or stopped meeting,
record under the same flag as manually started bots, and honour an explicit stop on
every path. Teams transcription routes the mixed audio into per-speaker windows from
the RTP transport's contributing sources; a speaker name stays provisional until the
roster has settled.

## Calendar & scheduled bots

- Multiple calendar feeds, managed from the dashboard: named, independently synced
  ICS connections; meetings deduplicate across feeds and keep every source visible
  ([#1150](https://github.com/Vexa-ai/vexa/issues/1150)).
- Bots dispatch two minutes before the scheduled start and wait up to fifteen
  minutes to be admitted ([#1210](https://github.com/Vexa-ai/vexa/issues/1210)).
- A failed auto-join retries on a bounded backoff, and the reason for the wait is
  readable on the meeting ([#1200](https://github.com/Vexa-ai/vexa/issues/1200)).
- A meeting already served or stopped is never re-armed; only genuine failures
  retry, and only within their own occurrence window
  ([#1211](https://github.com/Vexa-ai/vexa/issues/1211)).
- An explicit stop is stop: stopping a scheduled meeting cancels it before
  dispatch, a stop that races a starting bot leaves nothing running, and the stop
  is recorded as the outcome ([#1212](https://github.com/Vexa-ai/vexa/issues/1212)).
- Calendar auto-joined meetings are recorded like manually started ones
  ([#1217](https://github.com/Vexa-ai/vexa/issues/1217)).

## Teams

- CSRC transport activity routes the mixed audio into per-speaker transcription
  windows with the same buffering contract as Google Meet
  ([#499](https://github.com/Vexa-ai/vexa/issues/499) — attribution work; the
  exactly-once oracle that issue asks for stays open).
- A speaker name earned before the participant list is complete stays provisional
  and is corrected as evidence accumulates — no more locking one person's words
  under another's name ([#1228](https://github.com/Vexa-ai/vexa/pull/1228)).
- Names resolve from Teams' stable `data-tid` attributes instead of hashed CSS
  classes; only the `mainAudio` mix is transcribed, and double-mirrored tracks are
  deduplicated ([#1024](https://github.com/Vexa-ai/vexa/pull/1024)).

## Correctness & API surface

- One bot per meeting, even under concurrent requests; a request for a live
  meeting adopts the running bot ([#1185](https://github.com/Vexa-ai/vexa/issues/1185)).
- Self-hosted deployments fail closed when that guarantee cannot be enforced: the
  admin service refuses to start without the unique index
  ([#1187](https://github.com/Vexa-ai/vexa/issues/1187)).
- API keys only do what their scope allows — scope is enforced on bot lifecycle
  and user-config routes ([#1236](https://github.com/Vexa-ai/vexa/issues/1236)).
- Meeting responses ship owner-private fields (webhook URL, delivery config) to
  the owner and nothing sensitive to a transcript-share viewer
  ([#1243](https://github.com/Vexa-ai/vexa/pull/1243),
  [#1244](https://github.com/Vexa-ai/vexa/pull/1244)).
- Operator plumbing: admin identity by authoritative ID (#994), producer-observed
  service provenance on completed meetings (#984), optional external service
  authority (#988), signed system callback for terminal meeting facts (#992).

## Infrastructure

- Every deploy surface — Lite, Compose, Helm — now runs
  [Valkey](https://valkey.io) 8.1.9 instead of Redis
  ([#653](https://github.com/Vexa-ai/vexa/issues/653)).
- Release promotion copies registry manifest bytes exactly and reads back every
  frozen descriptor; nothing is rebuilt after the witness (#951).

## Docs

New guides and honest-status pages: [n8n](https://docs.vexa.ai/n8n) (#1076), the
[MCP server](https://docs.vexa.ai/vexa-mcp) boundary (#1077), share-links and
interactive-bots status (#1078, #1086), hosted-runs-0.12 start-here (#954),
signal-driven redirects (#1111), and FunASR validation attributed to the upstream
maintainers who ran it (#928).

## Getting it

Images are published multi-arch (`linux/amd64` + `linux/arm64`) under
`:v0.12.23`, byte-identical to the witnessed release candidate
(`v0.12.23-rc.21`). Lite and Docker Compose build and run green at this source.

## Upgrade notes

- **Self-hosted with an existing database:** the admin service now refuses to
  start if the one-bot-per-meeting unique index is missing (#1187). Apply the
  shipped schema migration before rolling this version; a fresh install needs
  nothing.
- The Redis→Valkey swap is transparent for stock deployments; custom images or
  pinned `redis:*` references need the new image name (#653).
- The declared `api.v1` surface has not been re-frozen for the routes added since
  0.12.18; the reconciliation is tracked in
  [#1234](https://github.com/Vexa-ai/vexa/issues/1234).

## Not claimed

- A transport-contested phrase on Teams is currently published under both
  contributing tracks — detected and counted in pipeline health, not yet
  resolved or marked in the public transcript (#499, documented in-repo as
  deliberately unresolved).
- Teams naming under heavy participant churn can still flap before settling;
  hysteresis and a fully deterministic CSRC→name path are tracked (#1229, #1230).
- Jitsi: the alone-leave timer and admitted→active lag have known residuals (#1214).
- A stop arriving before the meeting row exists is lost rather than remembered (#1213).
- Zoom: not updated in this release.

## Credits

Jacob Schooley ([@jbschooley](https://github.com/jbschooley)) — Teams speaker-name
resolution from stable `data-tid`, `mainAudio`-only transcription and track
dedup, from [#1024](https://github.com/Vexa-ai/vexa/pull/1024).

The FunASR maintainers ([@LauraGPT](https://github.com/LauraGPT)) — upstream
validation of the FunASR/SenseVoice custom-STT path
([#928](https://github.com/Vexa-ai/vexa/pull/928)).

Related Repositories