hermes-msteams-bridge (plugin name teams_call) is the Python half of the Teams CVI for
Hermes Agent. It hosts the HMAC WebSocket that StandIn connects to, runs the dialogue +
perception, and emits avatar driver cues. Chat-plane features live in the existing Teams adapter.
This adds voice/video (CVI) on top of Hermes Agent’s existing
Teams messaging - run both
for chat + calls.
Requirements
- A working Hermes Agent install (the host).
- A StandIn subscription (standin.komaa.com, free package) - the hosted media bridge connecting to this plugin. See Architecture.
- Realtime mode: an OpenAI / Azure OpenAI realtime key. Streaming mode: needs
ffmpegonPATH.
Install
Install into the same Python environment as Hermes so thehermes_agent.plugins entry-point is
discovered:
documents extra enables show_file document rendering (pypdfium2 +
Pillow). Optional system tools: LibreOffice (soffice on PATH) for showing
Office documents, ffmpeg for streaming-mode TTS decode. The show_web_page
tool uses the host Hermes browser tools - no extra install.
Or with pip:
plugins.enabled in
~/.hermes/config.yaml (the configuration page shows
the full block):
hermes plugins enable teams_call works too when run interactively, but it may
prompt for tool-override consent, so scripts and installers should write the
YAML instead.
Verify
Show config + readiness - the status probe checks every Hermes surface the plugin depends on (vision, STT, TTS, chat delivery, browser, document rendering) and reports two levels:boundaries_ok (the contract surface
exists) and operational_ok (providers/credentials/dependencies actually
work). Anything missing is named explicitly, so a broken Hermes integration
surfaces here and at serve startup rather than mid-call. External paths
(Teams reachability, the StandIn endpoint, provider round trips) are not
probed - those surface on the first real call. Tested against Hermes Agent
0.19.0 (PyPI floor) and the current 0.20.x line:
ws://<host>:8443/voice/msteams/stream).
Expose the WebSocket (Agent voice URL)
StandIn connects to your plugin from the internet, so port8443 must be reachable - a public
host, or a tunnel. With Tailscale Funnel, put voice on the 8443 slot (keeps the 443 slot free
for a Teams chat webhook):
Funnel serves up to 3 external ports (443, 8443, 10000). Also running the OpenClaw plugin on
the same machine? Use one canonical layout so the two runtimes never fight over a slot: keep
OpenClaw voice on 8443 -> 9442 and move Hermes voice to the 10000 slot:
tailscale funnel --bg --https=10000 8443 → wss://<machine>.<tailnet>.ts.net:10000/voice/msteams/stream.
Register each runtime as its own agent, each with its own secret. This matches the OpenClaw page, so
following both guides sets the same funnel map instead of overwriting the already-registered 8443 slot.Next: the full configuration reference - config.yaml +
.env, realtime
backend, and Graph permissions.Links
Source
PyPI
Configuration
Gateway-managed mode (one process)
With theteams_call platform enabled in the gateway config, hermes gateway run hosts the voice bridge itself - no separate serve process. Two layers
must both be on:
- the plugin:
teams_callunderplugins.enabledinconfig.yaml; - the platform: a
teams_callplatform entry enabled in the gateway configuration (same place as your Teams chat platform).
config.yaml shape:
deliver=teams_call - the bot calls you and speaks the result). If a
standalone hermes teams-call serve is already bound to the port, the
adapter fails loudly instead of splitting traffic - run one or the other.
Using the StandIn one-line installer? Set STANDIN_GATEWAY_MODE=1 in the
environment before running it: the installer then writes both layers
above, stops any standalone bridge, and restarts the gateway instead of
launching serve.
hermes teams-call smoke is an offline install check: it proves config
resolution, the HMAC handshake, wire decode, and session lifecycle against an
ephemeral local listener. It does not test the configured listener,
gateway platform activation, Teams connectivity, provider credentials, or the
public tunnel - the first real call is the test for those.