本文へ移動
cccskills
無料GitHub で公開

kortix-teams

How to CONNECT Microsoft Teams (`kortix channels connect --platform teams`, prints a tenant-admin consent URL) and how to answer in Teams as a teammate. Covers the live Adaptive Card stream (`teams step` with --detail/--output/--source, `teams send` to finalize the answer), sending and downloading files (the consent-card upload flow + `teams download`), reading teams/channels/members through connector calls, asking the user, and the tone the bot should use. Load this when the turn is triggered from Teams (the prompt mentions a Teams tenant/conversation, or `$MS_TEAMS_CONVERSATION_ID` is set in the env), or when the user asks how to do anything in Teams.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md20.3 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

<skill name="teams"> <connecting> **Everything below assumes Teams is already connected.** If the user is ASKING to connect it — or a `teams` command fails with no installation — that is one command, not a project:
kortix channels status --platform teams     # is this project connected?
kortix channels connect --platform teams    # prints the Microsoft admin-consent URL

connect prints an admin-consent URL. The user opens it and grants tenant-wide consent; the app is then published to their Teams catalog automatically. There is no app to create by hand and no token to paste — a Microsoft tenant admin has to be the one who approves it, so if the user isn't an admin, they need to forward that link to someone who is.

kortix channels disconnect --platform teams removes an installation; kortix channels manifest --platform teams prints the app manifest and is only for manual/self-host setup (the consent flow never needs it).

Channels vs personal chats. In a personal chat every message reaches you. In a team channel or group chat, Teams only delivers a message when the bot is @-mentioned — UNLESS the tenant admin has consented to the "receive all channel messages" permission, after which a reply in a thread the bot already owns continues the session without a mention. Either way, a new channel post needs the mention. </connecting>

<overview> Once connected, your sandbox is wired into Microsoft Teams. When a teammate `@`-mentions the bot or replies in a conversation the bot owns, the platform spins up this session and hands you the message; your turn IS the Teams reply.

The teams CLI is on $PATH and just works — there is no token in your sandbox and nothing to configure. Turn replies are owned and rendered by the Kortix server; vendor reads run through the Kortix connector gateway, which resolves the Microsoft Graph credential server-side. Don't look for an app password, don't reach for an MCP/HTTP workaround — just run the commands below. Two patterns matter most:

  • teams step "..." — narrate progress. Repaints the live Adaptive Card in the Teams conversation as you go.
  • teams send "..." — finalize the turn with your answer. This closes the live card and renders the reply. Markdown (headings, code, fenced blocks, tables, lists) is converted to card elements, so write normally.
  • teams send --card-file <path> — deliver a full Adaptive Card JSON as the reply instead of text, for rich layouts. The JSON's top-level type must be "AdaptiveCard".

Everything else (teams send --file, teams download, teams channels, …) is for when the task explicitly calls for it. </overview>

<live-stream> The Teams message you're replying to has a live **Adaptive Card** attached. Each `teams step` you emit appears as a new checkpoint in that card, updated in place in real time. Teammates can see what you're doing without waiting for the final answer.

teams step "<title>" — emit a checkpoint

Call this before each major step of your work. Keep titles short, human, and present-tense. A few per task — not one per shell command.

teams step "Reading the incident logs"
teams step "Cross-referencing with the deploy timeline"
teams step "Drafting the post-mortem"

--detail "<subtitle>" — short context line under the title

A one-line subtitle that explains what specifically you're doing in this step. Shown while the step is in progress.

teams step "Reading the incident logs" --detail "Last 24h, severity >= warn"

--output "<result>" — concrete result attached to the PREVIOUS step

When you start a new step and the previous one produced a concrete result, surface it with --output. It attaches to the step that's closing — the one transitioning to complete.

teams step "Cross-referencing the deploy timeline" \
  --output "Found 47 ERROR lines clustered around 14:32 UTC"

teams step "Drafting the post-mortem" \
  --output "3 candidate deploys in the window; api@a3f1 looks suspicious"

--source URL|TITLE — citation footer (repeatable)

Attach citations to the closing step. Pass multiple --source lines separated by newlines.

teams step "Drafting the post-mortem" \
  --output "3 candidate deploys" \
  --source $'https://github.com/acme/api/commit/a3f1|api@a3f1
https://datadog.example.com/dash/api-errors|Datadog dashboard'

Up to 8 sources per step; titles auto-trim at 80 chars.

So the natural pattern, end-to-end, looks like:

teams step "Reading the incident logs" --detail "Last 24h, severity >= warn"
# ... do the work ...
teams step "Cross-referencing the deploy timeline" \
  --output "47 ERROR lines around 14:32 UTC" \
  --detail "Walking back from the first error"
# ... do the work ...
teams step "Drafting the post-mortem" \
  --output "Pinned to api@a3f1 — auth middleware change" \
  --detail "Writing root cause + remediation"
# ... do the work ...
teams send "It was api@a3f1 — the new auth middleware drops the trace header on retries. Reverting now."

Rules

  • Mark phase transitions, not every shell call. ~3–6 per turn is right for most tasks; one per bash is noise.
  • Set --detail and --output once per step. They're truncated at 500 chars upstream; aim for one tight sentence.
  • Don't teams step after teams send. The card is closed once the answer ships; a later step from the same run is dropped. </live-stream>
<keeping-it-lively> Unlike Slack's streaming (which hard-fails after ~5 minutes of silence), the Teams live card is a posted message the server **edits in place**. It stays open as long as your run is alive, so a long, silent step (a build, a test suite) won't paint a false "error". That's the good news.

The flip side: Teams rate-limits how fast a message can be edited, so the server coalesces rapid updates. Two practical consequences:

  • Don't spam steps. Firing ten teams steps in two seconds is pointless — intermediate edits get dropped by the throttle and only the latest survives. Space them at real phase boundaries.
  • Still don't go dark for ages. A live run has no timeout to trip, but a wall of nothing for ten minutes is bad UX. Post a step before anything slow (git clone, pnpm install, a test suite, a build, deep research, a big LLM call) so the conversation always shows fresh, honest progress.

The rule of thumb: one checkpoint per meaningful phase — enough that a teammate watching always knows what's happening, not so many that you're fighting the throttle. </keeping-it-lively>

<final-answer> ### `teams send "<text>"` — deliver the answer
teams send "Reverted api@a3f1 — the new auth middleware dropped the trace header on retries. Errors are back to baseline."

This finalizes the live card: the plan flips to Task complete, your answer renders below it, and a link back to the Kortix session is appended automatically. The server wraps your text into the Adaptive Card — you don't build the card yourself; just write a clear, well-structured message.

  • One teams send per turn. It closes the card; a second call from the same run is dropped. If you have multiple things to say, fold them into one message.

  • Send the answer LAST. A teams step after it is dropped.

  • A link the user should open goes on its own line — it renders as a button:

    teams send "Gmail is not connected yet.
    
    [Connect Gmail](https://…)
    
    The link expires in 30 minutes. Reply **done** when you have connected it."
    

    Write the label as a short action (Connect Gmail, Open the pull request, Review the draft), at most 40 characters. Up to three link lines in one paragraph form a row of buttons; more stay a plain list. A connect link from kortix connectors connect is always a button, even inside a sentence. Every other link inside a sentence stays an ordinary link.

    </final-answer>
<asking-the-user> **Need to ask the user something with choices? Call the built-in `question` tool, then END your turn.**

It renders a real card, the same shape as asking in the Kortix app:

  • one question, up to 6 options, one answer → a button per option, one tap;
  • several questions, a multi-select, or more than 6 options → a form: each question with its options listed, a box for an answer of their own, and one Submit;
  • a question with no options → a text box.

Put the detail in each option's description — the card shows it. The user can always reply in the chat instead of using the card, so a closed list never traps them. The tool returns at once with a note telling you to end your turn — it does not block. The user's answer arrives as your NEXT turn, with full context. Don't sit waiting for it inside a turn.

A numbered list of choices written into teams send is the wrong shape: the user cannot tap it. Use teams send for a question only when it is genuinely open-ended prose with nothing to pick.

{
  "questions": [
    {
      "question": "Which environment should I deploy to?",
      "header": "Environment",          // shown above the question (max 30 chars)
      "options": [
        { "label": "Production", "description": "Live traffic; needs a rollback plan" },
        { "label": "Staging",    "description": "Mirrors prod data; safe to break" }
      ]
      // "multiple": true lets the user pick several
    }
  ]
}

The answer comes back labelled with its question, one line per question.

teams ask --form-file <path> — a form the question tool cannot express

When you need an input the question tool has no shape for — a date, a time, a number, a toggle — write the form yourself. Teams renders it as a card with real text boxes, dropdowns, toggles and one Submit button. Write a small JSON spec; the server builds the card.

cat > /tmp/form.json <<'JSON'
{
  "title": "Deploy details",
  "subtitle": "Two things before I start",
  "submitLabel": "Deploy",
  "fields": [
    { "id": "env", "label": "Environment", "type": "choice",
      "choices": ["prod", "staging"], "required": true },
    { "id": "notes", "label": "Anything I should know?", "type": "textarea" },
    { "id": "dry", "label": "Dry run first", "type": "toggle" }
  ]
}
JSON
teams ask --form-file /tmp/form.json --text "Before I deploy:"

Field type: text, textarea, number, date, time, choice, multichoice, toggle. Add placeholder, value (prefill) and required. Up to 12 fields, 24 choices each.

ask finalizes the turn, exactly like send. The user's Submit arrives as your NEXT turn with their answers, so post the form and then END your turn.

When you want to…Use
Ask anything with choices — one question or severalthe question tool
Ask for a date, time, number, or toggleteams ask --form-file
Ask something genuinely open-endedteams send with the question
Deliver the final answerteams send
Show progress along the wayteams step
Send a fileteams send --file

Whichever you use, the reply arrives as your NEXT turn. Ask, then END the turn. </asking-the-user>

<files-and-artifacts> ### Sending a file: `teams send --file <path>`

When the work produces an artifact (a PDF, CSV, report, diff, screenshot), offer it with --file. The server picks the delivery from the env — you always just run teams send --file:

  • An image (PNG, JPEG, GIF, WebP) → shown inline in the conversation, in every scope: personal chat, group chat, channel.
  • Any other file, personal chat → a file consent card: you offer the file, the user clicks Accept, and only then does Teams upload it. Two-step and asynchronous.
  • Any other file, channel → uploaded to the team's SharePoint drive and shared as a link card (needs the bot app's Files.ReadWrite.All permission — if it is missing, the command returns a clear error you can relay).
  • Any other file, group chat → not possible: Teams gives a bot no way to send a file into a group chat. Share a link in teams send instead.

An image too large for Teams to show inline falls back to the same path as any other file; in a group chat the command returns an error that asks for a smaller image.

The conversation context is taken from the env, so you don't pass IDs:

teams send --file /workspace/output/chart.png --text "Sign-ups by source"
teams send --file /workspace/output/report.pdf --text "Incident report — accept to download."
  • --text is the caption, or the consent-card description (what the user sees before accepting). Optional.
  • --file posts a separate message — it does not finalize the turn. Follow it with a regular teams send "..." to close the live card:
teams send --file /workspace/output/report.pdf --text "Full report — accept to download."
teams send "Pulled 12,847 sign-ups grouped by source. Report offered above; accept it to grab the PDF."
  • Upload limit ~4 MB. For anything larger, share a link in teams send instead of attaching.

Downloading a file shared in the conversation: teams download

When a teammate attaches a file to their message, its name and download URL are listed in your prompt under "Attached files". Pull it into the sandbox to work on it:

teams download --url "<downloadUrl from the prompt>" --out /workspace/incoming/data.csv

The download runs through the Kortix server (the credential stays server-side); you just give the URL and an output path.

Images: download, then just look at them

A pasted screenshot arrives as an attachment marked (image) — in a personal chat, a group chat, and a channel alike. Download it and open it with the read tool — you can see images directly.

teams download --url "<downloadUrl from the prompt>" --out /workspace/attachment.png
# then: read /workspace/attachment.png

Kortix runs an image-bearing turn on a model that can see images, so this works even when the conversation's usual model is text-only.

Do not go looking for OCR. ImageMagick, tesseract, PIL and an image-captioning API are all the wrong move — if read shows you the image, describe what you see. If it genuinely does not, say so in teams send rather than ending the turn silently. </files-and-artifacts>

<reading-the-conversation> ### `teams history` / `teams thread` — what was said before you were mentioned

In a channel the bot acts only on messages that @mention it. The discussion you were asked about is NOT in your session. Read it:

teams thread              # the thread you were mentioned in: the root post + every reply
teams history --limit 20  # recent posts in this channel

Both print JSON: messages[] with from, text (HTML stripped), at, and id, oldest first. Deleted and system messages are dropped. The channel, thread, and team come from the env — pass --team, --channel, or --message only to read somewhere else.

  • In a personal chat you need neither. Every message there already reaches this session. Both commands return NOT_A_CHANNEL.
  • NO_TEAM: Teams did not send the team id with this message. Pass --team <team-id> if the user gave you one; otherwise say in teams send that you cannot read the channel. Do not guess an id.
  • A 403 from Microsoft Graph means the Kortix app is not installed in that team, or the tenant has not granted it permission to read messages. Say so in teams send; do not retry.
  • conversation_not_in_project: every Kortix project in a tenant shares one app, so reads reach only this project's conversations. The channel or thread belongs to another project, or this project has no conversation in that channel while the tenant has several projects. Do not retry with another id. Say so in teams send, using the error's message.
  • teams history prints the help instead of JSON: this sandbox was built before the command existed. Say you cannot read the channel from here. </reading-the-conversation>
<posting-somewhere-else> ### Proactive posting — `teams post`

teams send answers the message you are handling. To post somewhere else — a nightly summary into a team channel, an alert, a hand-off note — use teams post. It does not touch the current turn.

teams conversations                                    # what you may post into
teams post --conversation "19:...@thread.tacv2" "Nightly build is green."
teams post --conversation "19:..." --card-file /tmp/report.json

teams post prints the posted message's messageId. Keep it to change the message later instead of posting a correction under it:

teams edit   --conversation "19:..." --message "<messageId>" "Nightly build is green (re-run)."
teams edit   --conversation "19:..." --message "<messageId>" --card-file /tmp/report.json
teams delete --conversation "19:..." --message "<messageId>"

Only a message the bot posted can be edited or deleted. Teams gives a bot no way to add a reaction.

You can only post into a chat or channel the bot is already in for this project. Anything else returns 404 — list the targets first rather than guessing an id. </posting-somewhere-else>

<other-surfaces> Reach for these only when the task explicitly asks. They run through the connector gateway against Microsoft Graph (read-only).

Look up teams, channels, members, users

teams team     --team "<team-id>"
teams channels --team "<team-id>"
teams channel  --team "<team-id>" --channel "<channel-id>"
teams members  --team "<team-id>"
teams user     --id "<user-id-or-upn>"

$MS_TEAMS_TENANT_ID, $MS_TEAMS_CONVERSATION_ID, $MS_TEAMS_SERVICE_URL, and $MS_TEAMS_USER_ID are pre-injected on Teams-triggered turns. Use them — don't hard-code IDs. Full help: teams help. </other-surfaces>

<tone> Reply like a colleague messaging on Teams:
  • No preamble. Don't open with "Sure!" / "I've taken a look and…". Get to the answer.
  • Standard Markdown. Teams Adaptive Cards render normal Markdown — **bold**, _italic_, `code`, [label](url) links, - bullet lists. This is the opposite of Slack — do NOT use Slack's *single-asterisk* bold or <url|label> links here; they render as literal text.
  • Short. A few sentences beat a wall of text. Use bullet lists for ≥3 items.
  • No XML, no "Here's a summary:" headers. This is a chat message, not a report. </tone>
<gotchas> - **Standard Markdown, not Slack mrkdwn.** `**bold**` and `[label](url)` — never `*bold*` / `<url|label>`. - **Send the answer last.** A `teams step` after `teams send` is dropped. - **Action links on their own line.** `[Connect Gmail](url)` alone on a line is a button; the same link mid-sentence is small underlined text. - **One `teams send` per turn** finalizes the card; a second call from the same run is dropped. After a `question` card, do not `teams send` at all — the card is your reply. - **Asking → the `question` tool + end the turn.** It renders a real card and returns at once; the answer is your next turn. An older copy of this skill said the tool had no Teams renderer — that is no longer true. - **`teams send --file`: an image is shown inline in every scope.** Any other file in a personal chat is a consent card — the user must Accept, and it does NOT finalize the turn, so follow it with a `teams send "..."`. In a channel a document becomes a drive link. An image too large to show inline falls back the same way; in a group chat it comes back as an error asking for a smaller one. Limit ~4 MB. - **Downloads come from the prompt.** Attached-file URLs are listed in your prompt; pass them to `teams download`. - **Don't go quiet on long work, but don't spam steps either** — Teams throttles card edits. One checkpoint per real phase. - **`$MS_TEAMS_*` env vars are pre-injected on Teams turns.** Use them; don't hard-code conversation/tenant IDs. </gotchas> </skill>

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Policy runbook for turning a Slack access request into a least-privilege, policy-checked GitHub or AWS IAM grant. Covers the role-to-grant mapping, extra-scrutiny cases, the approval handshake, and how an applied grant gets logged.

日本語の概要は準備中です。原文の説明を表示しています。

kortix-ai/suna2万2026年10月13日 更新

Get a complete picture of any company or person before outreach. This skill always works with web search, and gets significantly better with enrichment and CRM data.

日本語の概要は準備中です。原文の説明を表示しています。

kortix-ai/suna2万2026年10月13日 更新

Daily read-only ad-performance runbook — budget pacing, CPA/ROAS drift, underperforming ads and keywords, and anomaly detection across Google Ads and Meta Ads, plus how to rank and word optimization recommendations for {{alert_channel}}.

日本語の概要は準備中です。原文の説明を表示しています。

kortix-ai/suna2万2026年10月13日 更新

Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools.

日本語の概要は準備中です。原文の説明を表示しています。

kortix-ai/suna2万2026年10月13日 更新

Extraction, PO matching, duplicate detection, and overcharge tolerance for processing incoming vendor invoices from {{invoice_label}} against the POs and ledger in {{ap_ledger}}. Load this before extracting a single invoice so every one is checked to the same standard and only genuine exceptions reach a human, with no invoice ever scheduled for payment by the agent.

日本語の概要は準備中です。原文の説明を表示しています。

kortix-ai/suna2万2026年10月13日 更新

Daily brand-mention monitoring loop for {{brand_terms}}. Searches news, social platforms, and forums for new mentions, dedupes against the ledger of mentions already reported, classifies sentiment and notability, and posts a digest with suggested response drafts to {{slack_channel}} — never posts, replies, or comments anywhere.

日本語の概要は準備中です。原文の説明を表示しています。

kortix-ai/suna2万2026年10月13日 更新

kortix-ai のスキルをすべて見る

このスキルの問題を報告する