v0.12.27
ogx-ai/ogxv0.12.27Sep 7, 2026by DmitriyG228
Upgrading?
AI Summary
Introduces full MCP capabilities, a Python-based 'flows' system, and searchable meetings with metadata annotation.
Key Highlights
- Full MCP agent capabilities with friction reporting and standing notices
- Flows engine allowing Python code to orchestrate workflows
- Full-text search over meeting transcripts
- Security improvements stripping specific authority headers and webhook secrets
Breaking Changes
- Generate a real INTERNAL_API_SECRET (refuses placeholder values)
- POST /bots no longer returns webhook secrets (requires rotation)
- Person settings moved to identity (migration required)
- Agent surface routes behavior changed (404 vs 403 when unset)
New Features
- MCP `whats_waiting` tool
- Flows API (`POST /flows`)
- Meeting metadata annotation (`POST /meetings/{id}/annotate`)
- Full-text transcript search (`GET /transcripts/search`)
- Gateway header stripping for security
Full Release Notes
## v0.12.27
### MCP — an agent can do everything Vexa does, and it knows how
The tools describe themselves: what to call, in what order, and what to say when something is
refused. `whats_waiting` gives an agent its own queue on connect, scoped to its caller, each item
carrying the sentence to say and the typed reason behind it — a person with no meeting yet gets a
first step instead of an empty answer. A refusal comes back as `reason` / `message` / `action_url`
and the deciding service's own words, not prose to scrape. A word the edge did not expect is passed
to the owning route rather than rejected at the door.
- **Standing notices ride along with unrelated work (#1546, #1551, @DmitriyG228).** An item whose
copy declares itself a standing notice travels on the meeting tools' own results — and on their
refusals — so an agent hears it without going looking. `GET /queue/notices` asks for just those
sentences and nothing else.
- **Friction reporting (#1532, @DmitriyG228).** `report_friction` files what did not work; no field
is required and **no value a caller can send is refused** — an unknown word, an over-long value or
a missing session are all filed rather than rejected, because a report we cannot tie back to a
conversation is worth strictly more than no report. `friction_so_far` reads your own back.
- The queue's words come from files an admin edits, with no deploy on either side of the edit
(#1532, #1545, @DmitriyG228).
### Flows — a tiny n8n you can vibecode in Python
Event queuing, triggering and scheduling at the top-level API, so you can chain bots, agents,
calendar events — anything. `POST /flows` takes a name, a trigger and an ordered list of step names,
validated against the deployed vocabulary at submission and live in the worker in about ten seconds;
the API never accepts code, and steps are reviewed Python in the image. Ten Postgres tables in the
stack's own database — no message broker, no scheduler, no second state store. Dedup is a `UNIQUE`
constraint, "every effect exactly once" is a receipt, and every wait is a timestamp column.
Flows are global, not per-user: this is what you set up for a company when self-hosting, to chain
post-meeting summaries and the like.
- **`flows-api`, `flows-worker` and the optional `flows-mailbox` (#1456, @DmitriyG228)** — one image,
three commands. Documented at [Workflows](https://docs.vexa.ai/flows/overview).
- **The mailbox decides who it will act for before it admits anything (#1456, @DmitriyG228).** An
empty allow-list means the mailbox's own domain, not everyone; anybody else gets no account, no
agent turn and no model call — one `mail_quarantine` row, readable with one `SELECT`.
- **Tests, fixtures and the flows documentation (#1497, @DmitriyG228).**
### Meetings are searchable, and your agents can own them
Full-text search over your own transcripts (`GET /transcripts/search`; the index builds itself out of
band on first boot, without locking the table). Annotation from the API and from MCP: `POST
/meetings/{id}/annotate` attaches a title and arbitrary metadata during or after a meeting, and
`GET /meetings?metadata=` filters on it in the database (16 KB and 64 keys per meeting).
Once an agent annotates a meeting, it owns it — it tags each call with the deal it belongs to
(`{"opportunity": "acme-renewal", "stage": "technical-eval"}`) and later pulls every meeting on that
deal with one query, instead of guessing from titles and dates.
- **Address a meeting by its row id (#1547, @DmitriyG228).** `/meetings/{id}/…` and
`POST /meetings/{id}/share` beside the existing platform/native pair.
- **`GET /recordings` is a page, newest first (#1547, @DmitriyG228).** `limit` and `offset` on a list
shape.
- **Zoom served under a hosted or vanity hostname is recognised (#1547, @DmitriyG228).**
### Security
- **The gateway strips authority headers by family, not by name (#1456, @DmitriyG228).** At 0.12.26
the strip was an eight-name list of `x-user-*` spellings, so a public client could send
`x-internal-secret` — the value published in `docker-compose.yml` — and be believed by the internal
tier. Any header beginning `x-user-`, `x-internal-` or `x-vexa-internal-`, plus `x-admin-api-key`
and `x-gateway-verified`, is now dropped from every client request.
- **`POST /bots` no longer hands back the webhook signing secret it just stored (#1547,
@DmitriyG228).** The response was a verbatim copy of the stored row, so the secret travelled
through the public gateway into caller logs and agent context. Rotate any webhook secret minted by
an earlier version.
- **Boot refuses the published placeholder secrets (#1456, @DmitriyG228).** See *Upgrade notes*.
- **agent-api validates the workspace repository host and pins git transports (#1539,
@DmitriyG228).**
### Deployment
- **The agent surface is unchanged (#1553, @DmitriyG228).** `/agent/*` keeps the seven routes it
served at 0.12.26, now declared in `core/agent/routes.v1.json` like every other domain, with the
compose default restored. A deployment that leaves `AGENT_API_URL` unset serves no agent surface
and answers `404` there — at 0.12.26 the same state answered `403`.
- **Dependency floors across the Python, pnpm and transcript-rendering lockfiles (#1541, #1542,
#1544, @DmitriyG228).**
- **The ASWF 2020 v2 CCLA is accepted as an alternative corporate instrument (#1378,
@DmitriyG228).** A company whose legal has already approved that shape does not need a bespoke
one.
- **Carve manifest for the v0.12.26 train (#1418, @DmitriyG228).**
### Fixed
- **Asking for a Zoom bot through MCP could never work (#1631, @DmitriyG228).**
`request_meeting_bot` dropped the join URL for Zoom, and meeting-api refuses a Zoom request
without one — every attempt came back `422`. Meet, Teams and Jitsi were unaffected.
- **`/.well-known/mcp-tools.json` was served offline and absent live (@DmitriyG228)** — the module's
entrypoint guard sat above the route, so nothing below it ran in the process every deployment
starts.
- A person's settings move to identity, so one answer serves every service (#1456, @DmitriyG228) —
see *Upgrade notes*.
- One absence is said once, however many meetings ran into it (#1547, @DmitriyG228) — a deployment
that does not run the agent domain no longer adds an identical queue item per completed meeting.
- The friction sink never loses a report to a vocabulary word, and never to a missing one
(@DmitriyG228).
- `GET /reactions` answered `500` for every authenticated caller: the route shadowed the helper it
called (@DmitriyG228).
> **Known limit — three things this release does not finish.** The **person-settings import is
> operator-triggered**: settings move from the workspace file to identity, and an existing
> deployment that does not run the one-shot migration starts everyone on the defaults (mail on,
> clock in UTC) rather than on what they had. The **agent-half flow tests are skipped when the agent
> module is absent**, which is the shape OSS ships — those flows (`meeting_prep`, `email_chat`, the
> desk pair) are not registered at all without an agent domain, so their suites prove nothing here
> and are marked present-only. And **Python dependency licences are still unasserted**: the licence
> gate resolves the npm tree, `pip-licenses` scanning is owed rather than done (ADR-0009 §
> *Python licence scanning*), and the per-release SPDX carries those fields as `NOASSERTION`
> alongside the Ubuntu packages the Lite final stage installs. The gate is green on an inventory
> that does not actually assert those terms.
## Upgrade notes (breaking)
Read these before upgrading a self-hosted deployment. Each one changes behaviour that a 0.12.26
deployment relies on.
1. **Generate a real `INTERNAL_API_SECRET`.** Boot now refuses the literals this repo has published
(`vexa-internal-secret`, `lite-internal-secret`, `changeme`, …) and stops naming the variable. Use
`openssl rand -hex 32` and set the same value on every service that talks to another. Vexa Lite
mints a random one per boot and needs nothing set. `VEXA_FLOWS_API_KEY` has no default at all and
refuses the same placeholders — flows-api will not start without it.
2. **Upgrade the gateway with, or before, the services behind it.** The authority-header strip is now
a prefix family rule. Anything that was reaching an internal tier by sending its own
`x-internal-*` header through the public edge stops working — which is the point.
3. **MCP tool errors changed shape.** A refusal arrives as `reason` / `message` / `action_url` /
body, not as one sentence. Anything scraping the old text breaks. `notices` is a new key on five
tools' results.
4. **`/agent/*` answers `404`, not `403`, when `AGENT_API_URL` is unset.**
5. **Run the person-settings import.** Timezone and the mail switches are read from admin-api, not
from `.settings.json` in the workspace. Without the operator-triggered migration everyone reverts
to defaults — anyone who had mail off starts receiving it again, in UTC.
6. **`FLOWS_API_URL` → `VEXA_FLOWS_API_URL`** on admin-api. The old name is honoured for one release;
the new one wins when both are set.
7. **`X-Flows-Admin-Key` → `X-Flows-Operator-Key`.** Accepted for one release, with a warning once
per process. The old name read as admin-api's token, which it never was.
8. **`PROC_PENDING_GRACE_SEC` is removed.** No longer read; delete it from your `.env`.
9. **Copilot processed notes are no longer persisted after the bot stops.** The durable notes pane
and the schedule digest's `notes` flag stay empty once a meeting ends.
10. **Rotate any webhook signing secret minted before this release** — earlier `POST /bots` responses
returned it in the clear.
11. **Email lookups on the admin API are case-insensitive.** Reconcile existing case-variant
duplicate accounts before upgrading; which one resolves is otherwise plan-dependent.
12. **`flows` expects a database that has never held its tables.** The engine creates them with
`CREATE … IF NOT EXISTS` and ships no migration runner.
---
**Images (eleven — `vexaai/v012-flows` joins the release set with this version):** `vexaai/v012-admin-api@sha256:4c702354384eafe3a933cd537a106b7c15067cfd368a5f6da1a6e675e7e03e04`, `vexaai/v012-runtime@sha256:a1f6448fbb380b9433364e8b572ec25a12aa4f274bf403f1d83a89cbf5812f2d`, `vexaai/v012-agent-worker@sha256:a1120b24765ff6b1c86c5f9ddee35b5e71fdbb9543a23b918b278373ad705022`, `vexaai/v012-agent-api@sha256:6eb37574b33aab233aabbe5907e06e106bae44a403e5df781a436da8201a928d`, `vexaai/v012-meeting-api@sha256:4e9c201f656788755458fd6f2b9fbf3bfe0722d5b17d4cebd82b874b5aee98e1`, `vexaai/v012-gateway@sha256:2e76319812f28adbb6bc328ac0a7484d3826924a9d38a9dd9599dd190fbb0f19`, `vexaai/v012-mcp@sha256:4b2dbc08023ff424f40453d61a8f4d38a72de7eba1e5aaad1e428c309f63d338`, `vexaai/v012-terminal@sha256:8293350ff70008674032de67c682091eb8b87110412d2a4a1f3c4ed10cb1b09f`, `vexaai/vexa-bot@sha256:423c487aadb81514c71c9786758a3a730acbf5495e9593930da50c7442f158c1`, `vexaai/vexa-lite@sha256:945628e54d843cf6286a823ca8e226f2b3c48eb948ad2f895e64eb867b7a0d55`, `vexaai/v012-flows@sha256:e040c0de48924e78440e9cc4e71ed986471f101f99fbe5a5bd091af7e59996fa`, published from the reviewed candidate packet
`releases/v0.12.27/candidate-images.json` and validated by [run 34059966981](https://github.com/Vexa-ai/vexa/actions/runs/34059966981).
**In production:** this release is what vexa.ai runs. Pinned on the internal channel — the witnessed
packet as entry 35, and entry 36 carrying the same eleven OSS digests plus the release-version pin —
and re-verified against the cluster after each pin. All four platforms were walked live on the
witnessed packet before the tag was cut.
Related Repositories
public-apis/public-apis★ 491,135
A collective list of free APIs
NousResearch/hermes-agent★ 255,963
The agent that grows with you
yt-dlp/yt-dlp★ 200,054
A feature-rich command-line audio/video downloader
microsoft/markitdown★ 191,491
Python tool for converting files and office documents to Markdown.
Significant-Gravitas/AutoGPT★ 187,703
AutoGPT is the vision of accessible AI for everyone, to use and to build on. Our mission is to provide the tools, so that you can focus on what matters.