Skip to content

Instantly share code, notes, and snippets.

@jbgutierrez
Created April 17, 2026 15:36
Show Gist options
  • Select an option

  • Save jbgutierrez/5fcdbfec621ec830c9a5d2b2ecc9424e to your computer and use it in GitHub Desktop.

Select an option

Save jbgutierrez/5fcdbfec621ec830c9a5d2b2ecc9424e to your computer and use it in GitHub Desktop.
OpenCode command: /teams-reply — Send replies to Teams channel threads with channel memory via MemPalace
description Send a reply to a Teams channel thread. Remembers channels by name so you never need to paste the URL twice.

Message

$ARGUMENTS

Goal

Post a reply to a Teams channel thread via the Microsoft Graph API. Channels and threads are remembered in MemPalace so the user can reference them by short name (e.g., "Urgent Incidents") instead of pasting URLs every time.

Channel resolution

The user may reference the target in three ways (check in this order):

1. Teams URL provided

If $ARGUMENTS contains a Teams URL (teams.microsoft.com/l/message/...):

/usr/bin/python3 ~/.config/opencode/skills/reading-teams/scripts/teams.py parse-url "<URL>"

Extract team_id, channel_id, and thread_id from the output. Save the channel to MemPalace (see "Saving channels" below).

2. Channel name provided

If $ARGUMENTS mentions a channel by name (e.g., "Urgent Incidents", "General"):

mempalace_search(query="<channel_name>", wing="teams-channels")

Use the team_id, channel_id, and thread_id from the best matching drawer.

3. No channel specified

If the message has no URL and no recognizable channel name, search for the most recent channel:

mempalace_search(query="last-used", wing="teams-channels", room="last-used")

If nothing is found, ask the user which channel to use.

Saving channels to MemPalace

After resolving a channel (from URL or first use), save it for future reference:

mempalace_add_drawer(
  wing="teams-channels",
  room="saved",
  content="CHANNEL:<friendly_name>|team:<team_id>|channel:<channel_id>|thread:<thread_id>"
)

Also update the last-used pointer:

mempalace_add_drawer(
  wing="teams-channels",
  room="last-used",
  content="LAST-USED|<friendly_name>|team:<team_id>|channel:<channel_id>|thread:<thread_id>"
)

The friendly_name is derived from the URL parameter channelName (URL-decoded) or from the user's text. Strip emoji and normalize to a short, searchable label (e.g., "Urgent Incidents").

Thread update: If the user provides a new URL for an already-saved channel, update the thread_id in both saved and last-used rooms. The thread is the most recent conversation the user is interacting with.

Composing the message

Plain text

Wrap the user's text in proper HTML for Teams rendering. Use <br> for line breaks.

Mentions (@user)

If the message references a person (by name, username, or explicit @mention):

  1. Look up the user via Graph API:
TOKEN=$(cat ~/.cache/teams-token.json | /usr/bin/python3 -c "import json,sys; print(json.load(sys.stdin)['token'])")
curl -s "https://graph.microsoft.com/v1.0/users?\$filter=startswith(mailNickname,'<username>')&\$select=id,displayName,mail" \
  -H "Authorization: Bearer $TOKEN"
  1. If multiple results, ask the user to disambiguate.

  2. Include the mention in the request body:

{
  "body": {
    "contentType": "html",
    "content": "Message text <at id=\"0\">Display Name</at> more text"
  },
  "mentions": [
    {
      "id": 0,
      "mentionText": "Display Name",
      "mentioned": {
        "user": {
          "id": "<user_id>",
          "displayName": "Display Name",
          "userIdentityType": "aadUser"
        }
      }
    }
  ]
}

Sending the reply

Token refresh

Before sending, ensure the Graph token is valid:

/usr/bin/python3 ~/.config/opencode/skills/reading-teams/scripts/teams.py token

POST the reply

TOKEN=$(cat ~/.cache/teams-token.json | /usr/bin/python3 -c "import json,sys; print(json.load(sys.stdin)['token'])")

curl -s -X POST \
  "https://graph.microsoft.com/beta/teams/<team_id>/channels/<channel_id>/messages/<thread_id>/replies" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '<json_body>'

Important

  • Use /usr/bin/python3 (system Python) — the project .tool-versions blocks the asdf shim.
  • Use https://graph.microsoft.com/beta//v1.0/ returns 403 for channel messages.
  • The token key in ~/.cache/teams-token.json is token (not access_token).
  • Always use contentType: "html" for the message body.
  • Send directly — do NOT ask for confirmation (the user already requested to send).

Output

After successful send, report:

Publicado en <channel_name> (thread <thread_id>). Message ID: <id>

If the API returns an error, show the error and suggest running az login if it's auth-related.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment