Teams Presence
Teams Presence
Section titled “Teams Presence”Your meta-squad becomes a real participant in a Microsoft Teams channel. Address it by name — @artemis launch the frontend team — and get a response in-thread. It’s like having your AI team lead sitting in the channel, ready to execute federation commands, relay directives, and report status.
Under the hood, a persistent background process bridges Teams and a Copilot ACP session. Messages go in, results come back, all visible to the whole team.
How It Works
Section titled “How It Works”teams-presence.ts runs as a long-lived background process with a simple loop:
- Poll the Teams channel via Microsoft Graph API (default: every 30 seconds)
- Filter for messages addressing
@<federationName> - Pipe the instruction to a persistent Copilot ACP session
- Post the result back as a thread reply
- Advance the watermark so no message is processed twice
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐│ User types │ │ Graph API │ │ Copilot │ │ Graph API ││ @artemis ... │ ──▶ │ poll picks │ ──▶ │ ACP session │ ──▶ │ posts reply ││ in Teams │ │ it up │ │ executes │ │ to thread │└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘The watermark is persisted to disk (.squad/teams-watermark.json), so restarting the process won’t replay old messages.
Teams presence is configured during federation setup. The skill asks whether you want Teams integration and collects the required IDs.
What You Need
Section titled “What You Need”- Team ID — the GUID of your Teams workspace
- Channel ID — the
19:...@thread.tacv2identifier for the channel - Federation name — this becomes the
@handle(e.g.,@artemis)
Resulting Config
Section titled “Resulting Config”After setup, your federate.config.json includes:
{ "federationName": "artemis", "teamsConfig": { "teamId": "abc-123-def-456", "channelId": "19:xyz-789@thread.tacv2" }, "copilotCommand": "copilot"}The presence process starts automatically once setup completes with Teams enabled.
Introduction Message
Section titled “Introduction Message”When setup finishes, the squad posts an introduction to the channel:
👋 artemis is online. I’m your AI leadership squad. Mention
@artemisfollowed by an instruction and I’ll handle it.
Talking to Your Squad
Section titled “Talking to Your Squad”Type messages in the configured Teams channel. Prefix with your federation name:
@artemis what's the status of all teams?@artemis launch the frontend team@artemis pause backend@artemis tell infra to focus on the auth module@artemis sweep learnings across all domainsAnything after the @<name> is treated as a natural-language instruction and forwarded to the Copilot session.
What Happens
Section titled “What Happens”- Acknowledge — the presence immediately replies in-thread:
👋 Got it, Vladi. Working on: launch the frontend team…
- Execute — the instruction runs in the persistent Copilot ACP session
- Report — the result posts back as a thread reply with the output
If execution fails, the error is posted to the thread so you see it directly in Teams.
Managing Presence
Section titled “Managing Presence”Starting
Section titled “Starting”The presence auto-starts during federation setup when teamsConfig is present. To start manually:
npx tsx scripts/teams-presence.tsWith a custom poll interval (seconds):
npx tsx scripts/teams-presence.ts --interval 15Checking Status
Section titled “Checking Status”npx tsx scripts/teams-presence.ts --statusReports whether the process is running, the PID, last poll time, and watermark position.
Stopping
Section titled “Stopping”Cross-platform stop script:
node stop-presence.jsOr directly:
npx tsx scripts/teams-presence.ts --stopBoth read the PID from .squad/presence.pid and terminate the process.
Single Poll (Testing)
Section titled “Single Poll (Testing)”Run one poll cycle and exit — useful for debugging:
npx tsx scripts/teams-presence.ts --onceRequirements
Section titled “Requirements”| Requirement | Why |
|---|---|
az CLI, logged in | Graph API tokens via az account get-access-token |
copilot CLI available | ACP session for executing instructions |
| Teams channel access | Read/write messages in the configured channel |
federationName in config | Determines the @handle to filter for |
Architecture
Section titled “Architecture”The presence process has two layers:
Graph API Layer (Eyes & Mouth)
Section titled “Graph API Layer (Eyes & Mouth)”Fast, deterministic code that handles polling and posting. No AI involved.
- Calls
ListChannelMessageswith a watermark to get new messages - Filters for
@<federationName>mentions - Posts acknowledgments and results via
PostChannelMessage/ReplyToChannelMessage - Authenticates with
az account get-access-token --resource https://graph.microsoft.com
ACP Layer (Brain)
Section titled “ACP Layer (Brain)”A persistent Copilot session via the Agent Client Protocol. One session handles all instructions — no process spawn per message.
- Session stays alive between polls
- Full federation context available (config, team state, signals)
- Executes the same commands you’d run in a local Copilot conversation
| File | Purpose |
|---|---|
.squad/teams-watermark.json | Last processed message timestamp — prevents replay |
.squad/presence.pid | PID of the running presence process |
.squad/presence.log | Stdout/stderr from the background process |
Copilot Command
Section titled “Copilot Command”If your environment uses a wrapper or custom path to launch Copilot, set copilotCommand in federate.config.json:
{ "copilotCommand": "my-corporate-wrapper copilot"}The presence process uses this value when spawning the ACP session. Defaults to "copilot" if omitted.