🤖HermesBlog
Hermes Practical Guides · Part 288/9/2026

Teams Meeting Pipeline: Keeping Your Meeting Bot Alive

Teams Meeting Pipeline — easy-to-understand guide based on official docs

Guide: Teams Meeting Pipeline

Teams Meeting Pipeline: Keeping Your Meeting Bot Alive

So you’ve enabled the Teams Meeting Pipeline and your bot is starting to handle meetings. Now comes the part nobody tells you about: keeping it running smoothly. This guide walks you through the day-to-day operations, the critical maintenance you can’t skip, and how to fix things when they go wrong.

The One Thing You Must Do (Seriously)

Before we dive into commands, let’s talk about the biggest gotcha: Microsoft Graph subscriptions expire every 72 hours. If nothing renews them, your meeting notifications silently stop after three days. The pipeline looks fine, but nothing happens. This is the #1 reason Graph-backed integrations fail.

The fix? You must schedule maintain-subscriptions to run automatically. Here are your three options:

Option 1: Hermes Cron (Easiest)

If you already run the Hermes gateway, use its built-in scheduler. First, create a script:

mkdir -p ~/.hermes/scripts
cat > ~/.hermes/scripts/maintain-teams-subscriptions.sh <<'EOF'
#!/usr/bin/env bash
exec hermes teams-pipeline maintain-subscriptions
EOF
chmod +x ~/.hermes/scripts/maintain-teams-subscriptions.sh

Then register a job that runs every 12 hours (that’s 6x headroom against the 72-hour expiry):

hermes cron create "0 */12 * * *" \
  --name "teams-pipeline-maintain-subscriptions" \
  --no-agent \
  --script maintain-teams-subscriptions.sh \
  --deliver local

Verify it’s registered:

hermes cron list
hermes cron status

Option 2: systemd Timer (Linux Production)

Create a service file at /etc/systemd/system/hermes-teams-pipeline-maintain.service:

[Unit]
Description=Hermes Teams pipeline subscription maintenance
After=network-online.target

[Service]
Type=oneshot
User=hermes
EnvironmentFile=/etc/hermes/env
ExecStart=/usr/local/bin/hermes teams-pipeline maintain-subscriptions

And a timer at /etc/systemd/system/hermes-teams-pipeline-maintain.timer:

[Unit]
Description=Run Hermes Teams pipeline subscription maintenance every 12 hours

[Timer]
OnBootSec=5min
OnUnitActiveSec=12h
Persistent=true

[Install]
WantedBy=timers.target

Enable it:

sudo systemctl daemon-reload
sudo systemctl enable --now hermes-teams-pipeline-maintain.timer
systemctl list-timers hermes-teams-pipeline-maintain.timer

Option 3: Plain Crontab

Simple and effective:

0 */12 * * * /usr/local/bin/hermes teams-pipeline maintain-subscriptions >> /var/log/hermes/teams-pipeline-maintain.log 2>&1

Just make sure your cron environment has the MSGRAPH_* credentials. The easiest fix is sourcing ~/.hermes/.env at the top of a wrapper script.

Core Operator Commands

Here’s your daily toolkit:

  • Validate config: hermes teams-pipeline validate — run this after any config change
  • Check token health: hermes teams-pipeline token-health — add --force-refresh if you suspect stale auth
  • Inspect subscriptions: hermes teams-pipeline subscriptions
  • Renew near-expiry subscriptions: hermes teams-pipeline maintain-subscriptions (use --dry-run first)
  • List recent jobs: hermes teams-pipeline list — add --status failed to see problems
  • Show job details: hermes teams-pipeline show <job-id>
  • Replay a job: hermes teams-pipeline run <job-id>

Testing Meeting Fetches

You can dry-run fetching meeting artifacts:

hermes teams-pipeline fetch --meeting-id <meeting-id>
hermes teams-pipeline fetch --join-web-url "<join-url>"

Pro tip: For Teams /meet/ short URLs, you’ll need to pass --organizer-user-id <entra-user-id>. Graph rejects these URLs on the standard endpoint, but the organizer-scoped path works fine.

Routine Runbook

After first setup, run these in order:

hermes teams-pipeline validate
hermes teams-pipeline token-health --force-refresh
hermes teams-pipeline subscriptions

Then trigger a real meeting and confirm jobs appear:

hermes teams-pipeline list
hermes teams-pipeline show <job-id>

Daily checks:

  • Run maintain-subscriptions --dry-run to see if anything’s expiring
  • Check for failed jobs: list --status failed
  • Verify your Teams delivery target is still correct

Before changing webhook URLs or delivery targets:

  1. Update your config
  2. Run validate
  3. Renew affected subscriptions
  4. Confirm new events land where expected

Failure Triage

No jobs being created? Check that:

  • msgraph_webhook is enabled
  • Your public URL points to /msgraph/webhook
  • The client state matches MSGRAPH_WEBHOOK_CLIENT_STATE
  • Subscriptions exist remotely and haven’t expired

Jobs stuck in retry? Look at:

  • Transcript permissions and availability
  • Recording permissions
  • ffmpeg availability (if recording fallback is enabled)
  • Graph token health

Verifying Renewal Works

After setting up your schedule, check after the first run:

hermes teams-pipeline subscriptions  # expirationDateTime should have advanced
hermes teams-pipeline maintain-subscriptions --dry-run  # should show "0 expiring soon"

If your webhook mysteriously stops working after exactly ~72 hours, the renewal job didn’t run. That’s your first suspect, every time.

Keep this runbook handy, and your Teams Meeting Pipeline will hum along without surprises.

📖 Official Docs

This article is based on the official Hermes Agent documentation:Official docs › guides/operate-teams-meeting-pipeline