> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thor.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Meetings

> Convert meeting notes into actionable tasks and reminders for your team.

export const ChatLink = ({children}) => <span className="text-[#1264A3] dark:text-[#1D9BD1] underline underline-offset-2 decoration-[#1264A3]/40 dark:decoration-[#1D9BD1]/40 group-data-[chat=teams]:text-[#5B5FC7] group-data-[chat=teams]:dark:text-[#A6A7DC] group-data-[chat=teams]:decoration-[#5B5FC7]/40 group-data-[chat=mcp]:text-[#79c0ff] group-data-[chat=mcp]:decoration-[#79c0ff]/50 group-data-[chat=mcp]:no-underline font-medium break-all cursor-pointer">
    {children}
  </span>;

export const MsgSection = ({children}) => <div className="mb-2.5 last:mb-0">{children}</div>;

export const McpResult = ({children}) => <div className="hidden group-data-[chat=mcp]:block font-mono text-[13px] leading-relaxed mt-4">
    <div className="mb-1.5 flex items-center gap-2">
      <span className="rounded px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide bg-[#1f6feb]/25 text-[#79c0ff] border border-[#1f6feb]/40">
        thor
      </span>
      <span className="text-[11px] text-[#8b949e]">response</span>
    </div>
    <div className="rounded-md border border-[#1f6feb]/35 bg-[#0d1117] px-3 py-2.5 border-l-[3px] border-l-[#1f6feb]">
      <div className="min-w-0 text-[#c9d1d9] whitespace-pre-wrap">{children}</div>
    </div>
  </div>;

export const McpPrompt = ({children}) => <div className="hidden group-data-[chat=mcp]:block font-mono text-[13px] leading-relaxed">
    <div className="mb-1.5 flex items-center gap-2">
      <span className="rounded px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide bg-[#238636]/25 text-[#3fb950] border border-[#238636]/40">
        you
      </span>
      <span className="text-[11px] text-[#8b949e]">prompt</span>
    </div>
    <div className="rounded-md border border-[#30363d] bg-[#161b22] px-3 py-2.5">
      <div className="flex gap-2">
        <span className="shrink-0 select-none text-[#3fb950] font-bold">›</span>
        <div className="min-w-0 text-[#e6edf3]">{children}</div>
      </div>
    </div>
  </div>;

export const Mention = ({children}) => <>
    <span className="text-[#1264A3] dark:text-[#1D9BD1] font-medium group-data-[chat=teams]:hidden group-data-[chat=mcp]:hidden">
      @{children}
    </span>
    <span className="hidden group-data-[chat=teams]:inline-flex items-center rounded px-1 mx-0.5 text-[#5B5FC7] dark:text-[#A6A7DC] bg-[#5B5FC7]/10 dark:bg-[#5B5FC7]/20 font-medium">
      @{children}
    </span>
  </>;

export const Message = ({name, bot = false, self = false, time, color, avatar: avatarUrl, children}) => {
  const thorAvatar = "/images/thor-icon.svg";
  const youAvatar = "/images/you-avatar.jpg";
  const resolvedName = bot ? "Thor" : self ? "You" : name || "Alex";
  const resolvedColor = color || "#5095dd";
  const imageAvatar = avatarUrl || (bot ? thorAvatar : self ? youAvatar : null);
  const imagePad = bot && !avatarUrl;
  const avatarNode = () => {
    if (imageAvatar) {
      return <>
          <img src={imageAvatar} alt={resolvedName} className={`h-9 w-9 rounded-lg object-cover shrink-0 group-data-[chat=teams]:hidden ${imagePad ? "bg-[#D9E3E6] p-1.5 object-contain" : ""}`} />
          <img src={imageAvatar} alt={resolvedName} className={`hidden h-8 w-8 rounded-full object-cover shrink-0 group-data-[chat=teams]:block ${imagePad ? "bg-[#E8E8F0] dark:bg-[#2B2B36] p-1 object-contain" : ""}`} />
        </>;
    }
    return <>
        <div className="h-8 w-8 rounded-lg shrink-0 flex items-center justify-center text-white text-xs font-semibold group-data-[chat=teams]:hidden" style={{
      backgroundColor: resolvedColor
    }}>
          {resolvedName.slice(0, 1).toUpperCase()}
        </div>
        <div className="hidden h-8 w-8 rounded-full shrink-0 items-center justify-center text-white text-xs font-semibold group-data-[chat=teams]:flex" style={{
      backgroundColor: resolvedColor
    }}>
          {resolvedName.slice(0, 1).toUpperCase()}
        </div>
      </>;
  };
  return <>
      <div className="flex gap-2.5 items-start rounded-lg px-2 py-1.5 hover:bg-zinc-50 dark:hover:bg-white/5 group-data-[chat=teams]:hidden group-data-[chat=mcp]:hidden">
        {avatarNode()}
        <div className="min-w-0 flex-1">
          <div className="flex items-baseline gap-2 flex-wrap">
            <span className="text-[15px] font-bold text-zinc-900 dark:text-zinc-100">
              {resolvedName}
            </span>
            {bot ? <span className="rounded px-1 py-px text-[10px] font-bold uppercase tracking-wide bg-[#E8F5FA] text-[#1264A3] dark:bg-[#1D9BD1]/20 dark:text-[#1D9BD1]">
                App
              </span> : null}
            {time ? <span className="text-[12px] text-zinc-500">{time}</span> : null}
          </div>
          <div className="text-[15px] leading-relaxed text-zinc-800 dark:text-zinc-200 mt-0.5">
            {children}
          </div>
        </div>
      </div>

      <div className="hidden group-data-[chat=teams]:flex gap-2.5 items-start">
        {avatarNode()}
        <div className="min-w-0 max-w-[92%]">
          <div className="flex items-baseline gap-2 mb-1">
            <span className="text-[13px] font-semibold text-zinc-900 dark:text-zinc-100">
              {resolvedName}
            </span>
            {bot ? <span className="rounded px-1 py-px text-[10px] font-semibold uppercase tracking-wide bg-[#5B5FC7]/15 text-[#5B5FC7] dark:text-[#A6A7DC]">
                Bot
              </span> : null}
            {time ? <span className="text-[11px] text-zinc-500">{time}</span> : null}
          </div>
          <div className={`rounded-md px-3 py-2 text-[13px] leading-relaxed text-zinc-800 dark:text-zinc-100 shadow-sm ${bot ? "bg-white dark:bg-[#292929] border border-[#5B5FC7]/25" : "bg-white dark:bg-[#292929]"}`}>
            {children}
          </div>
        </div>
      </div>
    </>;
};

export const Conversation = ({channel = "general", type = "channel", defaultPlatform, platforms = "slack,teams,mcp", children}) => {
  const available = platforms.split(",").map(p => p.trim()).filter(Boolean);
  const initial = defaultPlatform && available.includes(defaultPlatform) ? defaultPlatform : available[0] || "slack";
  const [platform, setPlatform] = useState(initial);
  const thorAvatar = "/images/thor-icon.svg";
  const isDm = type === "dm";
  const title = isDm ? "Thor" : channel.replace(/^#/, "");
  const showTabs = available.length > 1;
  const tabClass = active => `inline-flex items-center gap-1.5 rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors ${active ? "bg-white dark:bg-zinc-800 text-zinc-900 dark:text-zinc-100 shadow-sm" : "text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-200"}`;
  const slackIcon = () => <svg viewBox="0 0 20 20" className="h-3.5 w-3.5" aria-hidden="true">
      <path fill="currentColor" d="M4.5 12.7a1.6 1.6 0 1 1-1.6-1.6h1.6v1.6zm.8 0a1.6 1.6 0 1 1 3.2 0v4a1.6 1.6 0 1 1-3.2 0v-4zM7.3 4.5a1.6 1.6 0 1 1 1.6-1.6v1.6H7.3zm0 .8a1.6 1.6 0 1 1 0 3.2h-4a1.6 1.6 0 1 1 0-3.2h4zM15.5 7.3a1.6 1.6 0 1 1 1.6 1.6h-1.6V7.3zm-.8 0a1.6 1.6 0 1 1-3.2 0v-4a1.6 1.6 0 1 1 3.2 0v4zM12.7 15.5a1.6 1.6 0 1 1-1.6 1.6v-1.6h1.6zm0-.8a1.6 1.6 0 1 1 0-3.2h4a1.6 1.6 0 1 1 0 3.2h-4z" />
    </svg>;
  const teamsIcon = () => <svg viewBox="0 0 20 20" className="h-3.5 w-3.5" aria-hidden="true">
      <path fill="currentColor" d="M11.2 4.2a2.4 2.4 0 1 1 2.5 2.4h-.1a2.4 2.4 0 0 1-2.4-2.4zm-6.3.6a2.1 2.1 0 1 1 2.2 2h-.1a2.1 2.1 0 0 1-2.1-2zm6.5 3.4h4.2c.8 0 1.4.6 1.4 1.4v4.1a3.4 3.4 0 0 1-3.4 3.4h-.3A4.3 4.3 0 0 0 17 13.2V8.8c0-.9-.7-1.6-1.6-1.6h-4zm-6.6.3h4.6c.7 0 1.3.6 1.3 1.3v5.1A3.7 3.7 0 0 1 7 18.6H6.3A3.7 3.7 0 0 1 2.6 14.9V9.8c0-.7.6-1.3 1.3-1.3z" />
    </svg>;
  const mcpIcon = () => <svg viewBox="0 0 20 20" className="h-3.5 w-3.5" aria-hidden="true">
      <path fill="currentColor" d="M4 5.5A1.5 1.5 0 0 1 5.5 4h9A1.5 1.5 0 0 1 16 5.5v9a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 4 14.5v-9zM6 7v1.5h1.75V7H6zm3.25 0v1.5H11V7H9.25zM12.5 7v1.5H14.25V7H12.5zM6 10v1.5h8.25V10H6zm0 3v1.5h5V13H6z" />
    </svg>;
  let frame;
  if (platform === "mcp") {
    frame = <div className="overflow-hidden rounded-xl border border-zinc-700 shadow-sm not-prose bg-[#0d1117]">
        <div className="flex items-center gap-2 border-b border-zinc-700/80 bg-[#161b22] px-3 py-2">
          <div className="flex items-center gap-1.5">
            <span className="h-2.5 w-2.5 rounded-full bg-[#ff5f56]" />
            <span className="h-2.5 w-2.5 rounded-full bg-[#ffbd2e]" />
            <span className="h-2.5 w-2.5 rounded-full bg-[#27c93f]" />
          </div>
          <div className="min-w-0 flex-1 text-center font-mono text-[11px] text-[#8b949e] truncate">
            thor mcp — cursor / claude
          </div>
          <div className="w-10" />
        </div>
        <div className="px-4 py-4 space-y-1 min-h-[7rem]">
          <div className="font-mono text-[11px] text-[#8b949e] mb-3">
            <span className="text-[#79c0ff]">mcp</span>
            <span className="text-[#8b949e]">:</span>
            <span className="text-[#a5d6ff]">thor</span>
            <span className="text-[#8b949e]">$ </span>
            <span className="text-[#c9d1d9]">ask</span>
          </div>
          {children}
          <div className="font-mono text-[13px] text-[#7ee787] mt-4 animate-pulse">
            ▍
          </div>
        </div>
      </div>;
  } else if (platform === "teams") {
    frame = <div className="overflow-hidden rounded-xl border border-zinc-200 dark:border-zinc-700 shadow-sm not-prose">
        <div className="flex items-center gap-2.5 bg-[#5B5FC7] px-3 py-2.5">
          {isDm ? <img src={thorAvatar} alt="" className="h-6 w-6 rounded-full bg-white/90 p-0.5 object-contain" /> : <div className="flex h-6 w-6 items-center justify-center rounded bg-white/15 text-white text-xs font-bold">
              #
            </div>}
          <div className="min-w-0">
            <div className="text-sm font-semibold text-white truncate">
              {title}
            </div>
            <div className="text-[11px] text-white/70">
              {isDm ? "Chat · Microsoft Teams" : "Microsoft Teams"}
            </div>
          </div>
        </div>
        <div className="bg-[#F5F5F5] dark:bg-[#1F1F1F] px-3 py-3 space-y-3">
          {children}
        </div>
      </div>;
  } else {
    frame = <div className="overflow-hidden rounded-xl border border-zinc-200 dark:border-zinc-700 shadow-sm not-prose">
        <div className="flex items-center gap-2 border-b border-zinc-200 dark:border-zinc-700 bg-white dark:bg-[#1A1D21] px-3 py-2.5">
          {isDm ? <img src={thorAvatar} alt="" className="h-5 w-5 rounded bg-[#D9E3E6] p-0.5 object-contain" /> : <span className="text-zinc-500 dark:text-zinc-400 text-lg leading-none">
              #
            </span>}
          <span className="text-sm font-bold text-zinc-900 dark:text-zinc-100">
            {title}
          </span>
        </div>
        <div className="bg-white dark:bg-[#1A1D21] px-2 py-3 space-y-1">
          {children}
        </div>
      </div>;
  }
  return <div className="my-4 not-prose group" data-chat={platform}>
      {showTabs ? <div className="mb-2 inline-flex flex-wrap items-center rounded-lg border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-900 p-0.5">
          {available.includes("slack") ? <button type="button" onClick={() => setPlatform("slack")} className={tabClass(platform === "slack")}>
              {slackIcon()}
              Slack
            </button> : null}
          {available.includes("teams") ? <button type="button" onClick={() => setPlatform("teams")} className={tabClass(platform === "teams")}>
              {teamsIcon()}
              Teams
            </button> : null}
          {available.includes("mcp") ? <button type="button" onClick={() => setPlatform("mcp")} className={tabClass(platform === "mcp")}>
              {mcpIcon()}
              MCP
            </button> : null}
        </div> : null}

      {frame}

      {platform === "mcp" && showTabs ? <p className="mt-2 text-xs text-zinc-500 dark:text-zinc-400">
          Same workflows via Thor's{" "}
          <a href="/usecases/mcp" className="underline underline-offset-2">
            MCP server
          </a>{" "}
          in Cursor, Claude, or any MCP client.
        </p> : null}
    </div>;
};

# Pre-requisites

To have Thor automatically take actions after your meetings end, you will need to connect at least one meeting transcription platform. Currently Thor supports **Google Meet** and **Zoom**.

<AccordionGroup>
  <Accordion icon="google" title="Google Meet Configuration">
    In order for Google Meet meetings to be captured by Thor, your Google Meet meetings need to have transcriptions enabled. For detailed Google Admin instructions on how to do this, see [Turn meeting transcription on or off](https://support.google.com/a/answer/12076932?hl=en). For detailed instructions on how to enable transcriptions for a specific meeting, see [Use Transcripts with Google Meet](https://support.google.com/meet/answer/12849897?hl=en).

    <Note>NOTE: Enabling Gemini notes and summaries is not required for Thor.</Note>
  </Accordion>

  <Accordion icon="video" title="Zoom Configuration">
    In order for Zoom meetings to be captured by Thor, your Zoom meetings need to have transcriptions enabled and cloud recording must be active. Additionally, all meeting participants must be signed-in members of your organization for Thor to process the meeting. For detailed instructions on how to enable audio transcripts for cloud recordings, see [How to enable audio transcripts for cloud recordings](https://support.zoom.com/hc/en/article?id=zm_kb\&sysparm_article=KB0065911).
  </Accordion>
</AccordionGroup>

# Use cases

## Get a summary of meeting action items and decisions

<iframe className="w-full aspect-video rounded-xl" src="https://www.youtube.com/embed/2fHoSmIVZRU" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen />

A few minutes after a meeting ends, Thor will automatically DM each participant with a list of action items and decisions from that meeting. If an action item was already discussed in an earlier meeting, Thor will flag it with a "Previously Discussed In" reference back to that conversation.

From there you can ask Thor to:

1. Create a task from an action item
2. Add a comment to an existing task (if one already exists)
3. Remind you about an action item later that day
4. Follow-up with you if you haven't completed the action item the next day

If you have multiple outstanding action items at the end of the day, Thor will batch them into a single end-of-day reminder rather than sending one message per item.

The message will look something like this:

<Conversation type="dm">
  <Message bot time="Today at 9:49 AM">
    <MsgSection>
      Here's a quick recap of action items from today's <ChatLink>Core Weekly Kick-off</ChatLink> meeting. Would you like me to create issues for them? I've also noted 1 decision below.
    </MsgSection>

    <MsgSection>
      <div className="border-t border-zinc-200 dark:border-zinc-600 my-2" />

      <div className="flex items-start justify-between gap-2">
        <span>
          <strong>1.</strong> Evaluate effort to support import from GitHub Projects for customers with single repo migrations.
        </span>

        <span className="shrink-0 rounded border border-zinc-300 dark:border-zinc-500 px-1.5 text-zinc-500 text-xs leading-5">⋯</span>
      </div>

      <div className="mt-1.5 italic text-zinc-600 dark:text-zinc-300">
        A customer trialing the platform wants to migrate a single GitHub Project into Zenhub; currently, there is no direct importer for this. Graeme will experiment to see if a solution can be developed or recommend alternatives.
      </div>

      <div className="mt-2 text-[13px] text-zinc-500 dark:text-zinc-400">
        💬 Previously discussed in meeting: <ChatLink>May 4 · 15 Min Meeting between Graeme Stapleton and Meg Reed</ChatLink>
      </div>
    </MsgSection>
  </Message>

  <McpPrompt>
    Use the Thor MCP to summarize action items from today's Core Weekly Kick-off.
  </McpPrompt>

  <McpResult>
    1. Evaluate effort to support import from GitHub Projects for single-repo migrations
       (Previously discussed: May 4 · Graeme Stapleton / Meg Reed)
  </McpResult>
</Conversation>

## Plan your day or week

Because Thor has access to your calendar, recent work activity and context on your most important goals, you can ask Thor to help you plan for your day, week or a specific meeting:

<Conversation type="dm">
  <Message self time="8:15 AM">
    Hey <Mention>Thor</Mention>, give me a plan for today.
  </Message>

  <Message bot time="8:15 AM">
    Here's a focused plan for today: **9:30** prep for the pricing sync, before lunch unblock ENG-1842 (Sam is waiting on your review), and **3:00** customer call with Acme. Want agendas for the rest of the week too?
  </Message>

  <McpPrompt>
    Use the Thor MCP to give me a plan for today.
  </McpPrompt>

  <McpResult>
    9:30 — prep pricing sync
    Before lunch — unblock ENG-1842 (Sam waiting on review)
    3:00 — Acme customer call (export + SSO)
  </McpResult>
</Conversation>

Other prompts that work well:

<Note>Hey `@Thor`, what important meetings do I have coming up this week? Generate a short agenda for each.</Note>
<Note>Hey `@Thor`, for my call with Tom later today, what should I be ready for?</Note>

## Find a decision made in a meeting

Have Thor do a deep scan of your recent meetings to find an important discussion point:

<Conversation type="dm">
  <Message self time="11:48 AM">
    Hey <Mention>Thor</Mention>, I remember a while back in some meeting we discussed migrating the code to Rust — can you find that discussion and remind me what we decided?
  </Message>

  <Message bot time="11:48 AM">
    Found it — **Platform sync, Mar 12**. Decision: stay on the current stack for now; revisit Rust only if the parser hotspot still shows up after the Q2 perf work. Want me to turn the follow-ups into tasks?
  </Message>

  <McpPrompt>
    Use the Thor MCP to find the meeting where we discussed migrating the code to Rust, and summarize what we decided.
  </McpPrompt>

  <McpResult>
    Platform sync, Mar 12 — stay on current stack; revisit Rust only if the parser hotspot remains after Q2 perf work.
  </McpResult>
</Conversation>

## Find a past discussion

Thor can also search across your threads to recover past conversations. When you link or forward a message, Thor loads the full thread (respecting private-channel access) and uses keyword-first matching with semantic fallback to find the right conversation:

<Conversation type="dm">
  <Message self time="3:02 PM">
    Hey <Mention>Thor</Mention>, I remember some time ago we were discussing the new pricing tiers in some channel. Help me find it.
  </Message>

  <Message bot time="3:02 PM">
    Closest match is the thread in **#product** from Apr 3 — "Pricing tiers v2". Summary: three tiers, annual discount at 20%, grandfather existing Pro customers. Want the link?
  </Message>

  <McpPrompt>
    Use the Thor MCP to find where we discussed the new pricing tiers.
  </McpPrompt>

  <McpResult>
    \#product · Apr 3 — "Pricing tiers v2"
    Three tiers, 20% annual discount, grandfather existing Pro customers.
  </McpResult>
</Conversation>
