Operate the Teams Meeting Pipeline
تشغيل خط اجتماعات Teams
What this page is, and what it holds.
This page covers Operate the Teams Meeting Pipeline. You will use hermes teams-pipeline validate and hermes teams-pipeline subscriptions here; about 6 minutes to read. Open the channel to yourself first with an allowlist. An open channel means anyone can message your agent.
Runbook, go-live checklist, and operator worksheet for the Microsoft Teams meeting pipeline
Outcomes taken from this page, not a template.
- Understand what بوابة المراسلة is and when you need it.
- Run
hermes teams-pipeline validateandhermes teams-pipeline subscriptionsand understand what happens next. - Read the table and take only the row that applies to you.
- Set
MSGRAPH_WEBHOOK_CLIENT_STATEin the right place.
Exactly as they appear in Hermes.
hermes teams-pipeline validatehermes teams-pipeline subscriptionshermes teams-pipeline runhermes teams-pipeline fetchhermes teams-pipeline maintain-subscriptionshermes cron createhermes teams-pipeline show
MSGRAPH_WEBHOOK_CLIENT_STATE
Jump to the part you need.
Nothing summarised away.
The documentation body below is reproduced from the official source so commands and identifiers stay exact. Each section carries a short note describing what it contains.
Use this guide after you have already enabled the feature from Teams Meetings.
This page covers:
- operator CLI flows
- routine subscription maintenance
- failure triage
- go-live checks
- rollout worksheet
Core Operator Commands
Ordered, practical steps. Run one and confirm it worked before moving on. Commands here: hermes cron status, hermes teams-pipeline subscriptions.
Validate the config snapshot
hermes teams-pipeline validateUse this first after any config change.
Inspect token health
hermes teams-pipeline token-health
hermes teams-pipeline token-health --force-refreshUse --force-refresh when you suspect stale auth state.
Inspect subscriptions
hermes teams-pipeline subscriptionsRenew near-expiry subscriptions
hermes teams-pipeline maintain-subscriptions
hermes teams-pipeline maintain-subscriptions --dry-runAutomating subscription renewal (REQUIRED for production)
Microsoft Graph subscriptions expire in at most 72 hours. If nothing renews them, meeting notifications silently stop after 3 days and the pipeline looks "broken." This is the #1 operational failure mode for any Graph-backed integration.
You MUST run maintain-subscriptions on a schedule. Pick one of these three options:
Option 1: Hermes cron (recommended if you already run the Hermes gateway)
Hermes ships a built-in cron scheduler. The --no-agent mode runs a script as the job (rather than using an LLM), and --script must point at a file under ~/.hermes/scripts/. First create the 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.shThen register a script-only cron job that runs every 12 hours (gives 6x headroom against the 72h expiry window):
hermes cron create "0 */12 * * *" \
--name "teams-pipeline-maintain-subscriptions" \
--no-agent \
--script maintain-teams-subscriptions.sh \
--deliver localVerify it was registered and inspect the next run time:
hermes cron list
hermes cron status # scheduler statusOption 2: systemd timer (recommended for Linux production deployments)
Create /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-subscriptionsAnd /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.targetEnable:
sudo systemctl daemon-reload
sudo systemctl enable --now hermes-teams-pipeline-maintain.timer
systemctl list-timers hermes-teams-pipeline-maintain.timerOption 3: Plain crontab
0 */12 * * * /usr/local/bin/hermes teams-pipeline maintain-subscriptions >> /var/log/hermes/teams-pipeline-maintain.log 2>&1Make sure the cron environment has the MSGRAPH_* credentials. Simplest fix: source ~/.hermes/.env at the top of a wrapper script that crontab calls.
Verifying renewal is working
After you've set up the schedule, check renewal activity after the first scheduled run:
hermes teams-pipeline subscriptions # should show expirationDateTime advanced
hermes teams-pipeline maintain-subscriptions --dry-run # should show "0 expiring soon" most of the timeIf you ever see your Graph webhook mysteriously "stop working" after exactly ~72 hours, this is the first thing to check: did the renewal job actually run?
Inspect recent jobs
hermes teams-pipeline list
hermes teams-pipeline list --status failed
hermes teams-pipeline show <job-id>Replay a stored job
hermes teams-pipeline run <job-id>Dry-run meeting artifact fetches
hermes teams-pipeline fetch --meeting-id <meeting-id>
hermes teams-pipeline fetch --join-web-url "<join-url>"Routine Runbook
Commands you type in a terminal. Understand what one does before copying it. Commands here: hermes teams-pipeline validate, hermes teams-pipeline subscriptions.
After first setup
Run these in order:
hermes teams-pipeline validate
hermes teams-pipeline token-health --force-refresh
hermes teams-pipeline subscriptionsThen trigger or wait for a real meeting event and confirm:
hermes teams-pipeline list
hermes teams-pipeline show <job-id>Daily or periodic checks
- run
hermes teams-pipeline maintain-subscriptions --dry-run - inspect
hermes teams-pipeline list --status failed - verify the Teams delivery target is still the correct chat or channel
Before changing webhook URLs or delivery targets
- update the public notification URL or Teams target config
- run
hermes teams-pipeline validate - renew or recreate affected subscriptions
- confirm new events land in the expected sink
Failure Triage
Settings you configure once. Change one at a time so you can see what each does. Commands here: hermes teams-pipeline run. Set MSGRAPH_WEBHOOK_CLIENT_STATE in your environment, not in the chat.
No jobs are being created
Check:
msgraph_webhookis enabled- the public notification URL points to
/msgraph/webhook - the client state in the subscription matches
MSGRAPH_WEBHOOK_CLIENT_STATE - subscriptions still exist remotely and are not expired
Jobs stay in retry or fail before summarization
Check:
- transcript permissions and availability
- recording permissions and artifact availability
ffmpegavailability if recording fallback is enabled- Graph token health
Summaries are produced but not delivered to Teams
Check:
platforms.teams.enabled: truedelivery_modeincoming_webhook_urlfor webhook modechat_idorteam_idpluschannel_idfor Graph mode- Teams auth config if Graph posting is used
Duplicate or unexpected replays
Check:
- whether you manually replayed a job with
hermes teams-pipeline run - whether the sink record already exists for that meeting
- whether you intentionally enabled a resend path in your local config
Go-Live Checklist
Settings you configure once. Change one at a time so you can see what each does. Commands here: hermes teams-pipeline validate. Set MSGRAPH_WEBHOOK_CLIENT_STATE in your environment, not in the chat.
- [ ] Graph credentials are present and correct
- [ ]
msgraph_webhookis enabled and reachable from the public internet - [ ]
MSGRAPH_WEBHOOK_CLIENT_STATEis set and matches subscriptions - [ ] transcript subscription is created
- [ ] recording subscription is created if STT fallback is required
- [ ]
ffmpegis installed if recording fallback is enabled - [ ] Teams outbound delivery target is configured and verified
- [ ] Notion and Linear sinks are configured only if actually needed
- [ ]
hermes teams-pipeline validatereturns an OK snapshot - [ ]
hermes teams-pipeline token-health --force-refreshsucceeds - [ ]
maintain-subscriptionsis scheduled (Hermes cron, systemd timer, or crontab — see Automating subscription renewal ↗). Without this, Graph subscriptions silently expire within 72 hours. - [ ] a real end-to-end meeting event has produced a stored job
- [ ] at least one summary has reached the intended delivery sink
Delivery-Mode Decision Guide
Explains the idea itself. Read it slowly; the later sections build on it.
| Mode | Use when | Tradeoff |
|---|---|---|
incoming_webhook | you only need simple posting into Teams | simplest setup, less control |
graph | you need channel or chat posting through Graph | more control, more auth and target config |
Operator Worksheet
A lookup table. Do not read it all; find the row that applies to you.
Fill this out before rollout:
| Item | Value |
|---|---|
| Public notification URL | |
| Graph tenant ID | |
| Graph client ID | |
| Webhook client state | |
| Transcript resource subscription | |
| Recording resource subscription | |
| Teams delivery mode | |
| Teams chat ID or team/channel | |
| Notion database ID | |
| Linear team ID | |
| Store path override, if any | |
| Owner for daily checks |
Change Review Worksheet
A lookup table. Do not read it all; find the row that applies to you.
Use this before changing the deployment:
| Question | Answer |
|---|---|
| Are we changing the public webhook URL? | |
| Are we rotating Graph credentials? | |
| Are we changing Teams delivery mode? | |
| Are we moving to a new Teams chat or channel? | |
| Do subscriptions need to be recreated or renewed? | |
| Do we need a fresh end-to-end verification run? |
4 questions answered by this page alone.
Every option is a real identifier from the Hermes documentation. The wrong ones are real too, just from other pages.