AutomationFlowsAI & RAG › Automatically Analyze Meeting Effectiveness with AI & Send Slack Feedback

Automatically Analyze Meeting Effectiveness with AI & Send Slack Feedback

ByJunichiro Tobe @junichiro on n8n.io

This workflow automatically analyzes meeting effectiveness and provides constructive feedback:

Event trigger★★★★☆ complexityAI-powered18 nodesAgentOpenAI ChatGoogle Drive ToolGoogle Docs ToolSlackMemory Buffer WindowGoogle Calendar TriggerGoogle Calendar
AI & RAG Trigger: Event Nodes: 18 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #9293 — we link there as the canonical source.

This workflow follows the Agent → Chat Trigger recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "650def54-b86d-444f-9d0f-0b20aa6ec372",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        448,
        32
      ],
      "parameters": {
        "options": {
          "systemMessage": "=# Meeting Coach AI System Prompt\n\nYou are a Meeting Coach AI that analyzes meeting effectiveness and provides constructive feedback.\n\n## Role and Purpose\n\nAnalyze meeting minutes or transcripts to provide objective and specific feedback on meeting effectiveness, communication quality, and areas for improvement. Avoid being overly critical and ensure to include actionable improvement suggestions.\n\n## Steps\n\n1. If there is a Google Docs URL for the meeting minutes, use it to retrieve the minutes from Google Drive. If not, search Google Drive using the meeting title name to retrieve the relevant minutes.\n2. If the meeting minutes cannot be found, report this and conclude.\n3. Review the retrieved meeting minutes to understand the full text and content.\n4. Compile feedback with the following content:\n\n## Analysis Items and Output Format\n\n### 1. Meeting Effectiveness\n\n- **Effectiveness Score**: Rate from 0% to 100%\n- Analyze from the following perspectives:\n  - **Meeting Purpose**: What was the goal of the meeting?\n  - **Achievements**: What was accomplished toward the goal?\n  - **Challenges**: What hindered the meeting's effectiveness (e.g., topic derailment, lack of focus)?\n  - **Conclusions and Next Steps**: Were specific decisions and action items clearly defined?\n\n### 2. Speaking Time Distribution\n\n- Display each participant's speaking time as a percentage\n- Comments on speaking balance:\n  - Was the balance appropriate?\n  - Was it a one-sided conversation?\n  - Suggestions for more effective dialogue\n\n### 3. Interruptions\n\n- Analyze whether there were significant interruptions and their impact on the meeting\n- Note if there were no interruptions\n\n### 4. Communication Quality\n\nRate each of the following items on a 5-star scale (\u2605\u2606\u2606\u2606\u2606 to \u2605\u2605\u2605\u2605\u2605) and provide specific comments:\n\n- **Clarity**: Were the agenda and opinions communicated clearly?\n  - \u2605\u2606\u2606\u2606\u2606: Very unclear\n  - \u2605\u2605\u2606\u2606\u2606: Unclear\n  - \u2605\u2605\u2605\u2606\u2606: Average\n  - \u2605\u2605\u2605\u2605\u2606: Clear\n  - \u2605\u2605\u2605\u2605\u2605: Very clear\n\n- **Friendliness**: Was the atmosphere cooperative and positive?\n  - \u2605\u2606\u2606\u2606\u2606: Hostile\n  - \u2605\u2605\u2606\u2606\u2606: Somewhat cold\n  - \u2605\u2605\u2605\u2606\u2606: Average\n  - \u2605\u2605\u2605\u2605\u2606: Friendly\n  - \u2605\u2605\u2605\u2605\u2605: Very friendly\n\n- **Decisiveness**: Were decisions and next actions clearly defined?\n  - \u2605\u2606\u2606\u2606\u2606: No decisions made\n  - \u2605\u2605\u2606\u2606\u2606: Ambiguous\n  - \u2605\u2605\u2605\u2606\u2606: Some decisions\n  - \u2605\u2605\u2605\u2605\u2606: Clear decisions\n  - \u2605\u2605\u2605\u2605\u2605: Very clear decisions and actions\n\n- **Listening**: Did participants listen to and try to understand each other's opinions?\n  - \u2605\u2606\u2606\u2606\u2606: Not listening at all\n  - \u2605\u2605\u2606\u2606\u2606: Not listening much\n  - \u2605\u2605\u2605\u2606\u2606: Average\n  - \u2605\u2605\u2605\u2605\u2606: Listening well\n  - \u2605\u2605\u2605\u2605\u2605: Listening very well\n\nFor each item:\n- Quote specific examples of what went well from the conversation\n- Points that could be improved and specific suggestions\n\n### 5. Disagreements\n\n- List topics that became points of discussion\n- Briefly explain each participant's position\n- Note whether issues were resolved or remained unresolved\n- If there were no conflicts, note \"None in particular\"\n\n### 6. Meeting Info\n\n- Meeting title (extract from minutes, or \"Unknown\" if unavailable)\n- List of participants\n\n## Tone and Style\n\n- **Constructive**: Provide insights for growth, not criticism\n- **Specific**: Quote concrete examples from the conversation rather than abstract evaluations\n- **Balanced**: Point out both strengths and areas for improvement\n- **Practical**: Include improvement suggestions that can be implemented immediately\n\n## Output Format\n\n**Meeting Effectiveness** \u2192 **[Your evaluated score]%**\n* [Analysis of meeting purpose]\n* [What was achieved]\n* [Challenges]\n* [Evaluation of conclusions and next steps]\n\n**Speaking Time Distribution**\n* **[Participant name]**: [Your calculated percentage]%\n* **[Participant name]**: [Your calculated percentage]%\n* [Comments on speaking balance]\n* [Improvement suggestions]\n\n**Interruptions**\n* [Analysis of presence and impact of interruptions]\n\n**Communication Quality**\n* [Your evaluated number of \u2605s] **| Clarity**: [Evaluation comment]\n* [Your evaluated number of \u2605s] **| Friendliness**: [Evaluation comment]\n* [Your evaluated number of \u2605s] **| Decisiveness**: [Evaluation comment]\n* [Your evaluated number of \u2605s] **| Listening**: [Evaluation comment]\n* [Specific improvement suggestions and examples of positive points]\n\n**Disagreements**\n\u274c [Topic name]:\n1. **[Participant name]**: [Explanation of position]\n2. **[Participant name]**: [Explanation of position]\n3. **Resolution status**: [Explanation of whether consensus was reached or issue remains unresolved]\n\n(If no conflicts: \"There were no significant disagreements.\")\n\n**Meeting Info**\n* **Meeting Title**: [Title]\n* **Participants**: [Participant list]\n\n---\n\nWhen meeting minutes or transcripts are provided, analyze and provide feedback following the above format. Evaluate each assessment item appropriately based on the actual meeting content."
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "199072fb-3fb9-440d-aa57-44dc6afb2bee",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        368,
        240
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5",
          "cachedResultName": "gpt-5"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "0194fded-a382-47e8-8cec-0a6936df9faa",
      "name": "SearchDoc",
      "type": "n8n-nodes-base.googleDriveTool",
      "position": [
        576,
        416
      ],
      "parameters": {
        "limit": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Limit', ``, 'number') }}",
        "filter": {
          "whatToSearch": "files"
        },
        "options": {},
        "resource": "fileFolder",
        "queryString": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Search_Query', ``, 'string') }}"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "4a61eb43-d664-493b-887e-c412d6652dfc",
      "name": "GetDoc",
      "type": "n8n-nodes-base.googleDocsTool",
      "position": [
        672,
        240
      ],
      "parameters": {
        "operation": "get",
        "documentURL": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Doc_ID_or_URL', ``, 'string') }}"
      },
      "credentials": {
        "googleDocsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "9d1fa3ac-5030-416e-8020-b2eec0c1f1b4",
      "name": "Send a message",
      "type": "n8n-nodes-base.slack",
      "position": [
        1040,
        240
      ],
      "parameters": {
        "text": "=\u30c6\u30b9\u30c8",
        "user": {
          "__rl": true,
          "mode": "id",
          "value": "U03H0J4KU7R"
        },
        "select": "user",
        "blocksUi": "={{ $json.slackPayload }}",
        "messageType": "block",
        "otherOptions": {
          "mrkdwn": true
        },
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "e9a57402-de45-403f-8f0c-b764dffb7a5c",
      "name": "Simple Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        448,
        416
      ],
      "parameters": {},
      "typeVersion": 1.3
    },
    {
      "id": "22b64ef2-5672-43c7-9a8c-e761447eedc1",
      "name": "Google Calendar Trigger",
      "type": "n8n-nodes-base.googleCalendarTrigger",
      "position": [
        -672,
        240
      ],
      "parameters": {
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "triggerOn": "eventEnded",
        "calendarId": {
          "__rl": true,
          "mode": "id",
          "value": "=[your-id]"
        }
      },
      "credentials": {
        "googleCalendarOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "c70fd6b4-5428-44ab-8080-f4a10a35de58",
      "name": "Edit Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        112,
        240
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "82a8a73d-5c24-4c67-aed4-8d3f26ccf8f8",
              "name": "chatInput",
              "type": "string",
              "value": "={{ $json.summary }} \u3068\u3044\u3046\u30bf\u30a4\u30c8\u30eb\u306e\u4f1a\u8b70\u3092\u884c\u3044 {{ $json.attachment[0].fileUrl }} \u3068\u3044\u3046 URL \u306e Google Docs \u306b\u6c17\u8b70\u4e8b\u9332\u3092\u4fdd\u5b58\u3057\u307e\u3057\u305f\n\nGoogle Docs \u306e fileId \u306f {{ $json.attachment[0].fileId }} \u3067\u3059"
            },
            {
              "id": "3f8f99b5-9cf2-4005-b1fc-cc89fa79183a",
              "name": "=sessionId",
              "type": "string",
              "value": "=a {{ $json.id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "e468e662-b2fa-4f8a-b01d-e0213cdb4d40",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        -496,
        240
      ],
      "parameters": {
        "unit": "minutes"
      },
      "typeVersion": 1.1
    },
    {
      "id": "8cbf5fe5-879c-456a-9b4d-66d1f04f0b26",
      "name": "Get an event",
      "type": "n8n-nodes-base.googleCalendar",
      "position": [
        -336,
        240
      ],
      "parameters": {
        "eventId": "={{ $json.id }}",
        "options": {},
        "calendar": {
          "__rl": true,
          "mode": "id",
          "value": "=[your-id]"
        },
        "operation": "get"
      },
      "credentials": {
        "googleCalendarOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "ed8ecac5-c3c2-464b-8cfe-540a76525187",
      "name": "Test Trigger",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        -160,
        32
      ],
      "parameters": {
        "options": {
          "responseMode": "lastNode"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "398412f8-29fa-49eb-ac55-cfef96469809",
      "name": "Code",
      "type": "n8n-nodes-base.code",
      "position": [
        896,
        240
      ],
      "parameters": {
        "jsCode": "/**\n * n8n Code node (JavaScript)\n * \u5165\u529b:  $input.first().json.output \u306b Markdown\u98a8\u306e\u9577\u6587\uff08\u5b9f\u6539\u884c or \u30ea\u30c6\u30e9\u30eb \"\\n\"\uff09\n * \u51fa\u529b:  \u6700\u521d\u306e\u30a2\u30a4\u30c6\u30e0\u306b\u4ee5\u4e0b\u3092\u683c\u7d0d\n *   - json.blocks: Array<Block>\uff08Block Kit \u306e\u914d\u5217\uff09\n *   - json.slackPayload: { blocks: Array<Block> }  // \u2190 UI Builder \u3068\u540c\u3058\u30c8\u30c3\u30d7\u30ec\u30d9\u30eb\n *   - json.text_fallback: Slack text \u7528\u30d5\u30a9\u30fc\u30eb\u30d0\u30c3\u30af\n *\n * \u6b21\u30ce\u30fc\u30c9\uff08Slack \u9001\u4fe1\u4f8b\uff09:\n *   - Body JSON \u306b {{$json.slackPayload}} \u3092\u305d\u306e\u307e\u307e\u4f7f\u3046\n *   - \u3082\u3057\u304f\u306f blocks: {{$json.blocks}}, text: {{$json.text_fallback}}\n */\n\n// ===== Utils =====\nfunction toActualNewlines(s) {\n  if (typeof s !== 'string') return '';\n  return s.replace(/\\r\\n?/g, '\\n').replace(/\\\\n/g, '\\n');\n}\n\n// \u30a4\u30f3\u30e9\u30a4\u30f3: *bold* / **bold**, _italic_, `code`, [text](url)\nfunction tokenizeInline(text) {\n  const tokens = [];\n  let i = 0;\n\n  const pushPlain = (t) => { if (t) tokens.push({ type: 'text', text: t }); };\n\n  const patterns = [\n    { // code\n      re: /`([^`]+)`/g,\n      build: (m) => ({ type: 'text', text: m[1], style: { code: true } }),\n    },\n    { // bold **...**\n      re: /\\*\\*([^*]+)\\*\\*/g,\n      build: (m) => ({ type: 'text', text: m[1], style: { bold: true } }),\n    },\n    { // bold *...* \uff08\u5148\u982d\u306e\u7b87\u6761\u66f8\u304d \"* \" \u3068\u885d\u7a81\u3057\u306a\u3044\u3088\u3046\u8abf\u6574\uff09\n      re: /(^|[^*])\\*([^*\\n]+)\\*(?!\\*)/g,\n      build: (m) => [{ type: 'text', text: m[1] || '' }, { type: 'text', text: m[2], style: { bold: true } }],\n      isComposite: true,\n    },\n    { // italic _..._\n      re: /_([^_]+)_/g,\n      build: (m) => ({ type: 'text', text: m[1], style: { italic: true } }),\n    },\n    { // link [text](url)\n      re: /\\[([^\\]]+)\\]\\((https?:\\/\\/[^\\s)]+)\\)/g,\n      build: (m) => ({ type: 'link', url: m[2], text: m[1] }),\n    },\n  ];\n\n  while (i < text.length) {\n    let earliest = null, pat = null;\n    for (const p of patterns) {\n      p.re.lastIndex = i;\n      const m = p.re.exec(text);\n      if (m && (!earliest || m.index < earliest.index)) {\n        earliest = m; pat = p;\n      }\n    }\n    if (!earliest) { pushPlain(text.slice(i)); break; }\n\n    if (earliest.index > i) pushPlain(text.slice(i, earliest.index));\n\n    if (pat.isComposite) {\n      const built = pat.build(earliest);\n      for (const b of built) if (b.text !== '') tokens.push(b);\n    } else {\n      tokens.push(pat.build(earliest));\n    }\n\n    i = earliest.index + earliest[0].length;\n  }\n\n  return tokens.length ? tokens : [{ type: 'text', text }];\n}\n\nfunction makeSectionElementsFromText(t) {\n  return tokenizeInline(t);\n}\n\n// ===== Block builders =====\nfunction headerBlock(text) {\n  return { type: 'header', text: { type: 'plain_text', text: text.slice(0, 150) } };\n}\nfunction paragraphBlock(text) {\n  return { type: 'rich_text', elements: [{ type: 'rich_text_section', elements: makeSectionElementsFromText(text) }] };\n}\nfunction quoteBlock(lines) {\n  const elements = lines.map(l => ({ type: 'rich_text_section', elements: makeSectionElementsFromText(l) }));\n  return { type: 'rich_text', elements: [{ type: 'rich_text_quote', elements }] };\n}\nfunction preBlock(lines) {\n  return { type: 'rich_text', elements: [{ type: 'rich_text_preformatted', elements: [{ type: 'text', text: lines.join('\\n') }] }] };\n}\nfunction listBlock(style, indent, sections) {\n  return { type: 'rich_text', elements: [{ type: 'rich_text_list', style, indent, elements: sections }] };\n}\n\n// ===== Parser =====\nfunction convertMarkdownToBlocks(mdRaw) {\n  const md = toActualNewlines(mdRaw);\n  const lines = md.split('\\n');\n  const blocks = [];\n\n  let inCode = false, codeBuf = [];\n  let inQuote = false, quoteBuf = [];\n\n  // \u30ea\u30b9\u30c8\u72b6\u614b\uff08style/indent \u3067\u675f\u306d\u308b\uff09\n  let listActive = false, listStyle = null, listIndent = 0, listItems = [];\n\n  const flushQuote = () => {\n    if (inQuote && quoteBuf.length) blocks.push(quoteBlock(quoteBuf));\n    inQuote = false; quoteBuf = [];\n  };\n  const flushList = () => {\n    if (listActive && listItems.length) blocks.push(listBlock(listStyle, listIndent, listItems));\n    listActive = false; listStyle = null; listIndent = 0; listItems = [];\n  };\n  const startList = (style, indent) => {\n    if (!listActive || listStyle !== style || listIndent !== indent) {\n      flushList();\n      listActive = true; listStyle = style; listIndent = indent; listItems = [];\n    }\n  };\n\n  const parseListLine = (line) => {\n    const leading = (line.match(/^\\s*/)[0] || '').length;\n    const trimmed = line.trim();\n    if (/^[-*\u2022]\\s+/.test(trimmed)) {\n      return { style: 'bullet', indent: Math.floor(leading / 2), text: trimmed.replace(/^[-*\u2022]\\s+/, '') };\n    }\n    const m = trimmed.match(/^(\\d+)\\.\\s+(.+)$/);\n    if (m) {\n      return { style: 'ordered', indent: Math.floor(leading / 2), text: m[2] };\n    }\n    return null;\n  };\n\n  for (let i = 0; i < lines.length; i++) {\n    const raw = lines[i];\n\n    // ``` code fence\n    if (/^\\s*```/.test(raw)) {\n      flushQuote(); flushList();\n      if (!inCode) { inCode = true; codeBuf = []; }\n      else { blocks.push(preBlock(codeBuf)); inCode = false; codeBuf = []; }\n      continue;\n    }\n    if (inCode) { codeBuf.push(raw); continue; }\n\n    // \u7a7a\u884c\u306f\u533a\u5207\u308a\n    if (/^\\s*$/.test(raw)) {\n      flushQuote(); flushList();\n      continue;\n    }\n\n    // \u5f15\u7528\n    if (/^\\s*>+\\s?/.test(raw)) {\n      flushList();\n      const q = raw.replace(/^\\s*>+\\s?/, '');\n      inQuote = true; quoteBuf.push(q);\n      continue;\n    } else if (inQuote) {\n      flushQuote();\n    }\n\n    // \u898b\u51fa\u3057\uff08#\u301c### or **\u898b\u51fa\u3057** \u5358\u72ec\u884c\uff09\n    if (/^\\s*#{1,3}\\s+/.test(raw) || /^\\s*\\*\\*(.+?)\\*\\*\\s*$/.test(raw)) {\n      flushQuote(); flushList();\n      const text = /^\\s*#{1,3}\\s+/.test(raw)\n        ? raw.replace(/^\\s*#{1,3}\\s+/, '').trim()\n        : (raw.match(/^\\s*\\*\\*(.+?)\\*\\*\\s*$/)[1] || '').trim();\n      blocks.push(headerBlock(text));\n      continue;\n    }\n\n    // \u30ea\u30b9\u30c8\n    const li = parseListLine(raw);\n    if (li) {\n      flushQuote();\n      startList(li.style, li.indent);\n      listItems.push({ type: 'rich_text_section', elements: makeSectionElementsFromText(li.text) });\n      continue;\n    } else {\n      flushList();\n    }\n\n    // \u901a\u5e38\u6bb5\u843d\n    blocks.push(paragraphBlock(raw));\n  }\n\n  // \u6b8b\u308a\n  if (inCode && codeBuf.length) blocks.push(preBlock(codeBuf));\n  flushQuote(); flushList();\n\n  return blocks;\n}\n\n// ===== Main =====\nconst items = $input.all();\nconst first = $input.first();\nconst source = first?.json?.output ?? '';\n\nconst blocks = convertMarkdownToBlocks(source);\n\n// text_fallback: \u6700\u521d\u306e header / paragraph \u3092\u62bd\u51fa\nlet textFallback = 'Message';\nfor (const b of blocks) {\n  if (b.type === 'header') { textFallback = b.text?.text?.slice(0, 300) || textFallback; break; }\n  if (b.type === 'rich_text') {\n    const el = b.elements?.[0];\n    if (el?.type === 'rich_text_section') {\n      const s = (el.elements || [])\n        .map(e => e.type === 'text' ? e.text : (e.type === 'link' ? (e.text || e.url) : ''))\n        .join('');\n      if (s) { textFallback = s.slice(0, 300); break; }\n    }\n  }\n}\n\n// \u8fd4\u5374\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\uff08UI Builder \u3068\u540c\u3058\u30c8\u30c3\u30d7\u306b blocks\uff09\nfirst.json.blocks = blocks;                 // \u914d\u5217\uff08\u5fc5\u8981\u306a\u3089\u3053\u3061\u3089\u3092\u76f4\u63a5\u4f7f\u3046\uff09\nfirst.json.slackPayload = { blocks };       // \u2190 \u671f\u5f85\u3069\u304a\u308a\u306e { \"blocks\": [...] }\nfirst.json.text_fallback = textFallback;\n\nreturn items;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "bc7b5908-d4b5-4d91-b682-59b98c30d79b",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        -160,
        240
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "6385b3c0-7c81-46f4-81cd-3693ea460ab1",
              "operator": {
                "type": "boolean",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.attachment }} ",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "d7a63115-97ba-4022-9338-f7ab40252b56",
      "name": "No Operation, do nothing",
      "type": "n8n-nodes-base.noOp",
      "position": [
        112,
        448
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "71f79653-49b9-4faa-bd5b-2787ab8bb30a",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -752,
        -48
      ],
      "parameters": {
        "width": 768,
        "height": 656,
        "content": "## Triggers\n* End of Google Calendar Event\n* Chat Trigger for testing"
      },
      "typeVersion": 1
    },
    {
      "id": "a42391fb-cda2-438e-957b-8c342f505842",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        48,
        -48
      ],
      "parameters": {
        "color": 4,
        "height": 464,
        "content": "## Adjust format\nAdjust input format for next node that is AI Agent"
      },
      "typeVersion": 1
    },
    {
      "id": "5f128546-5780-48c4-967e-eb81fff4f611",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        320,
        -48
      ],
      "parameters": {
        "color": 5,
        "width": 496,
        "height": 656,
        "content": "## AI node\nThis AI Agent analyze your meeting transcription, and give a feedback."
      },
      "typeVersion": 1
    },
    {
      "id": "65be1eda-c622-4bd6-83b9-1c066b55427d",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        848,
        -48
      ],
      "parameters": {
        "color": 3,
        "width": 384,
        "height": 656,
        "content": "## Output node \n* Changet format from regular markdown to Slack mrkdown by code node\n* Post a slack message\n* You can change the settings to send other channels"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Operation, do nothing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code": {
      "main": [
        [
          {
            "node": "Send a message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait": {
      "main": [
        [
          {
            "node": "Get an event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GetDoc": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SearchDoc": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get an event": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Test Trigger": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Google Calendar Trigger": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow automatically analyzes meeting effectiveness and provides constructive feedback:

Source: https://n8n.io/workflows/9293/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

BoomerBobBot.TP. Uses agent, telegramTrigger, telegram, memoryBufferWindow. Event-driven trigger; 95 nodes.

Agent, Telegram Trigger, Telegram +10
AI & RAG

My workflow 7. Uses lmChatOpenRouter, slackTrigger, chatTrigger, agent. Event-driven trigger; 37 nodes.

OpenRouter Chat, Slack Trigger, Chat Trigger +7
AI & RAG

✨ Overview

OpenAI Chat, Memory Buffer Window, Tool Workflow +5
AI & RAG

Inverview Scheduler. Uses lmChatOpenAi, memoryBufferWindow, toolWorkflow, stickyNote. Event-driven trigger; 25 nodes.

OpenAI Chat, Memory Buffer Window, Tool Workflow +5
AI & RAG

Stop forgetting to send follow-up surveys. This workflow automatically generates a tailored post-meeting survey from your Google Meet notes the moment a meeting ends, and sends it to all attendees wit

Google Calendar Trigger, Google Calendar, Google Docs +6