AutomationFlowsAI & RAG › Coach Fitness and Nutrition on Telegram with Claude, Google Sheets and Calendar

Coach Fitness and Nutrition on Telegram with Claude, Google Sheets and Calendar

ByDr. Firas @drfiras on n8n.io

This workflow turns a Telegram bot into a fitness and nutrition coach powered by Anthropic Claude, with voice-note transcription via OpenAI, user data stored in Google Sheets, and optional workout scheduling in Google Calendar. Triggers when a new Telegram message arrives in…

Event trigger★★★★☆ complexityAI-powered26 nodesTelegram TriggerTelegramOpenAIAgentAnthropic ChatMemory Buffer WindowGoogle Sheets ToolGoogle Calendar Tool
AI & RAG Trigger: Event Nodes: 26 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Agent → Google Calendar Tool 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
{
  "id": "62KYZrAAC9DFCRMI",
  "meta": {
    "builderVariant": "mcp",
    "aiBuilderAssisted": true
  },
  "name": "Coach fitness and nutrition on Telegram with Claude, Google Sheets and Calendar",
  "tags": [],
  "nodes": [
    {
      "id": "f518cb88-e89c-4617-aa02-9de84528dce6",
      "name": "Receive Telegram message",
      "type": "n8n-nodes-base.telegramTrigger",
      "position": [
        0,
        112
      ],
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "e58bcd0d-e1ba-4942-811d-1d7d4f57acef",
      "name": "Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        224,
        112
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cfg-coach-language",
              "name": "coach_language",
              "type": "string",
              "value": "French"
            },
            {
              "id": "cfg-transcription-language",
              "name": "transcription_language",
              "type": "string",
              "value": "fr"
            },
            {
              "id": "cfg-date-format",
              "name": "date_format",
              "type": "string",
              "value": "dd/MM/yyyy"
            },
            {
              "id": "cfg-memory-context-length",
              "name": "memory_context_length",
              "type": "number",
              "value": 15
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "273fac60-9983-4452-a6d4-44245a2abc16",
      "name": "Check for voice message",
      "type": "n8n-nodes-base.if",
      "position": [
        448,
        112
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "or",
          "conditions": [
            {
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.message.voice.file_unique_id }}",
              "rightValue": ""
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.3
    },
    {
      "id": "23122dc8-063a-4093-95ca-add86fb13b0b",
      "name": "Download voice message",
      "type": "n8n-nodes-base.telegram",
      "position": [
        672,
        64
      ],
      "parameters": {
        "fileId": "={{ $('Receive Telegram message').item.json.message.voice.file_id }}",
        "resource": "file",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "61fb8fec-d6fb-4e86-a1e3-57b6810ab789",
      "name": "Transcribe voice with OpenAI",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        896,
        64
      ],
      "parameters": {
        "options": {
          "language": "={{ $('Configuration').item.json.transcription_language }}"
        },
        "resource": "audio",
        "operation": "transcribe"
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "4e8acdeb-ac74-4261-862d-e3fe0c9ef484",
      "name": "Normalize user message",
      "type": "n8n-nodes-base.set",
      "position": [
        1232,
        64
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "nm-user-message",
              "name": "user_message",
              "type": "string",
              "value": "={{ $('Receive Telegram message').item.json.message.text || $json.text }}"
            },
            {
              "id": "nm-chat-id",
              "name": "chat_id",
              "type": "string",
              "value": "={{ $('Receive Telegram message').item.json.message.chat.id }}"
            },
            {
              "id": "nm-current-date",
              "name": "current_date",
              "type": "string",
              "value": "={{ $now.toFormat($('Configuration').item.json.date_format) }}"
            },
            {
              "id": "nm-weekday",
              "name": "weekday",
              "type": "string",
              "value": "={{ $now.setLocale('fr').toFormat('cccc') }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "ed969d6a-a07e-4724-9eae-3815169385b4",
      "name": "AI fitness coach agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1776,
        64
      ],
      "parameters": {
        "text": "={{ $json.user_message }}",
        "options": {
          "maxIterations": 40,
          "systemMessage": "=# R\u00d4LE\nTu es un coach sportif personnel et expert en nutrition. Tu accompagnes l'utilisateur vers ses objectifs de forme avec un suivi rigoureux, personnalis\u00e9 et bienveillant. Tu t'exprimes TOUJOURS en {{ $('Configuration').item.json.coach_language === 'French' ? 'fran\u00e7ais' : $('Configuration').item.json.coach_language }}, sur un ton motivant, professionnel et exigeant.\n\n# POSTURE : \u00c9TAT D'ESPRIT DE D\u00c9VELOPPEMENT\nTu adoptes en permanence une mentalit\u00e9 de d\u00e9veloppement (growth mindset). Cette posture PRIME sur le ton motivant : tu restes exigeant et honn\u00eate, jamais flatteur.\n- Quand l'utilisateur rate une s\u00e9ance ou stagne, ne le rassure pas \u00e0 vide. Extrais la le\u00e7on concr\u00e8te et donne la prochaine action pr\u00e9cise. Un \u00e9chec est une donn\u00e9e, pas un verdict.\n- Reformule tout \u00ab je n'y arrive pas \u00bb en \u00ab pas ENCORE \u00bb, et montre le chemin.\n- F\u00e9licite le PROCESSUS : effort, r\u00e9gularit\u00e9, m\u00e9thode. Ne f\u00e9licite JAMAIS un talent suppos\u00e9.\n- Quand l'utilisateur se d\u00e9valorise, consulte Read workout history pour lui rappeler des preuves concr\u00e8tes de sa progression, puis recentre-le sur la prochaine action.\n\n# TES OUTILS\n- Read user profile : lire le profil (poids, objectif, niveau, blessures).\n- Update user profile : modifier une donn\u00e9e du profil (usage strict, voir r\u00e8gle de s\u00e9curit\u00e9).\n- Log workout session : enregistrer une s\u00e9ance r\u00e9alis\u00e9e.\n- Read workout history : consulter l'historique des s\u00e9ances.\n- Log meal in nutrition journal : enregistrer un repas consomm\u00e9.\n- Read today meals : lire les repas du jour pour un bilan.\n- Save weekly nutrition plan : cr\u00e9er/mettre \u00e0 jour le plan de repas et la liste de courses.\n- Save weekly training plan : cr\u00e9er/mettre \u00e0 jour le programme de la semaine.\n- Read weekly training plan : consulter le programme de la semaine.\n- Create workout event in Calendar : planifier une s\u00e9ance dans l'agenda.\n\n# CONNAISSANCE DE L'UTILISATEUR\n- Avant tout conseil personnalis\u00e9, consulte Read user profile.\n- Tiens TOUJOURS compte des blessures : adapte les exercices pour ne jamais les aggraver.\n\n# ENREGISTREMENT DES DONN\u00c9ES\n- S\u00e9ance termin\u00e9e rapport\u00e9e (exercice, charge, r\u00e9p\u00e9titions) : utilise Log workout session.\n- REPAS, R\u00c8GLE DE QUANTIT\u00c9 : AVANT d'estimer les macros, v\u00e9rifie que la quantit\u00e9 est exploitable (grammes ou portions concr\u00e8tes). Si elle est absente ou trop vague, DEMANDE la quantit\u00e9 et N'ENREGISTRE RIEN tant que tu ne l'as pas. Une fois la quantit\u00e9 connue, estime calories et macros puis utilise Log meal in nutrition journal. Dans ta confirmation, indique la quantit\u00e9 retenue comme base de calcul.\n- Confirme tout enregistrement de mani\u00e8re br\u00e8ve et valorisante (processus, pas talent).\n\n# PLANS DE LA SEMAINE\n- Plan de repas demand\u00e9 : r\u00e9dige-le et enregistre-le avec Save weekly nutrition plan.\n- Programme d'entra\u00eenement demand\u00e9 : r\u00e9dige-le et enregistre-le avec Save weekly training plan.\n- Ces plans REMPLACENT le pr\u00e9c\u00e9dent. Apr\u00e8s enregistrement, confirme simplement.\n\n# MODIFICATION DU PROFIL (R\u00c8GLE DE S\u00c9CURIT\u00c9 STRICTE)\n- N'utilise Update user profile QUE si l'utilisateur demande EXPLICITEMENT de modifier une donn\u00e9e.\n- Ne modifie QUE le champ demand\u00e9. JAMAIS de ta propre initiative.\n\n# MISE EN FORME DES PLANS\n- Texte simple (jamais de HTML ni de Markdown), tr\u00e8s a\u00e9r\u00e9 : une ligne vide entre sections et jours, titres en MAJUSCULES avec un emoji, un \u00e9l\u00e9ment par ligne commen\u00e7ant par \u00ab \u2022 \u00bb, liste de courses group\u00e9e par cat\u00e9gorie.\n\n# MESSAGES VOCAUX\n- Les messages peuvent venir de transcriptions audio : ignore les fautes propres \u00e0 l'oral, concentre-toi sur l'intention.\n\n# STYLE DE R\u00c9PONSE\n- R\u00e9ponses claires, a\u00e9r\u00e9es, adapt\u00e9es \u00e0 Telegram. Termine souvent par une question ouverte.\n\nDate actuelle : {{ $json.current_date }}\nJour de la semaine : {{ $json.weekday }}"
        },
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "70e316f0-c14d-4b1c-a7b5-ad63906b1476",
      "name": "Claude chat model",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        1168,
        512
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "claude-sonnet-4-6",
          "cachedResultName": "Claude Sonnet 4.6"
        },
        "options": {}
      },
      "typeVersion": 1.5
    },
    {
      "id": "846a6d26-e35a-4c5f-b622-e268b8e1d147",
      "name": "Session memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        1328,
        512
      ],
      "parameters": {
        "sessionKey": "={{ $('Normalize user message').item.json.chat_id }}",
        "sessionIdType": "customKey",
        "contextWindowLength": "={{ $('Configuration').item.json.memory_context_length }}"
      },
      "typeVersion": 1.4
    },
    {
      "id": "581afb6c-7ab5-4a3c-9540-c40b06c734c0",
      "name": "Read user profile",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        1488,
        512
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $('Normalize user message').item.json.chat_id }}",
              "lookupColumn": "id_telegram"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "profil"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "AI fitness coach data"
        },
        "descriptionType": "manual",
        "toolDescription": "Utile pour r\u00e9cup\u00e9rer le profil complet du sportif (poids actuel, objectif, niveau, blessures) \u00e0 partir de son ID Telegram (chat_id). \u00c0 consulter avant tout conseil personnalis\u00e9."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "28b4719b-f505-42e9-acc7-a822332b3797",
      "name": "Update user profile",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        1648,
        512
      ],
      "parameters": {
        "columns": {
          "value": {
            "objectif": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('objectif', 'Nouvel objectif du sportif, uniquement si demand\u00e9 explicitement') }}",
            "id_telegram": "={{ $('Normalize user message').item.json.chat_id }}",
            "poids_actuel": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('poids_actuel', 'Nouveau poids actuel du sportif, uniquement si demand\u00e9 explicitement') }}"
          },
          "schema": [
            {
              "id": "id_telegram",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "id_telegram",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "poids_actuel",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "poids_actuel",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "objectif",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "objectif",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id_telegram"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "profil"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "AI fitness coach data"
        },
        "descriptionType": "manual",
        "toolDescription": "Utile UNIQUEMENT pour modifier une donn\u00e9e pr\u00e9cise du profil quand l'utilisateur le demande EXPLICITEMENT (ex: change mon poids \u00e0 78 kg, mon objectif est maintenant l'endurance). Ne modifier QUE le champ demand\u00e9. NE JAMAIS utiliser cet outil de ta propre initiative ni pour compl\u00e9ter des champs manquants."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "9b98a973-8916-4eb2-bce0-e9530d41d9cc",
      "name": "Log workout session",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        1824,
        512
      ],
      "parameters": {
        "columns": {
          "value": {
            "date": "={{ $('Normalize user message').item.json.current_date }}",
            "exercice": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('exercice', 'Nom des exercices r\u00e9alis\u00e9s pendant la s\u00e9ance') }}",
            "id_telegram": "={{ $('Normalize user message').item.json.chat_id }}",
            "performance": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('performance', 'D\u00e9tail des performances: charges, s\u00e9ries, r\u00e9p\u00e9titions, dur\u00e9e') }}"
          },
          "schema": [
            {
              "id": "id_telegram",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "id_telegram",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "date",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "exercice",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "exercice",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "performance",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "performance",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "historique"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "AI fitness coach data"
        },
        "descriptionType": "manual",
        "toolDescription": "Utile pour enregistrer une s\u00e9ance termin\u00e9e dans l'historique. \u00c0 utiliser uniquement quand l'utilisateur annonce une performance r\u00e9alis\u00e9e (exercice, charge, r\u00e9p\u00e9titions). Ne pas utiliser pour une simple question."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "6b325f7e-e0df-429e-abab-99a6ee6f3d6d",
      "name": "Read workout history",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        2000,
        512
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $('Normalize user message').item.json.chat_id }}",
              "lookupColumn": "id_telegram"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "historique"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "AI fitness coach data"
        },
        "descriptionType": "manual",
        "toolDescription": "Utile pour CONSULTER l'historique des s\u00e9ances pass\u00e9es afin d'analyser la progression (comparer les performances, voir la derni\u00e8re s\u00e9ance, le volume d'entra\u00eenement). NE PAS utiliser pour enregistrer une nouvelle s\u00e9ance, c'est le r\u00f4le de Log workout session."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "86e4869e-e35c-4ed2-9f27-9cc679dbcace",
      "name": "Log meal in nutrition journal",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        2160,
        512
      ],
      "parameters": {
        "columns": {
          "value": {
            "date": "={{ $('Normalize user message').item.json.current_date }}",
            "repas": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('repas', 'Description du repas consomm\u00e9 avec la quantit\u00e9 retenue') }}",
            "lipides": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('lipides', 'Estimation des lipides en grammes') }}",
            "calories": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('calories', 'Estimation des calories du repas') }}",
            "glucides": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('glucides', 'Estimation des glucides en grammes') }}",
            "proteines": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('proteines', 'Estimation des prot\u00e9ines en grammes') }}",
            "id_telegram": "={{ $('Normalize user message').item.json.chat_id }}"
          },
          "schema": [
            {
              "id": "id_telegram",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "id_telegram",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "date",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "repas",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "repas",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "calories",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "calories",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "proteines",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "proteines",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "lipides",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "lipides",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "glucides",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "glucides",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "nutrition"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "AI fitness coach data"
        },
        "descriptionType": "manual",
        "toolDescription": "Utile pour enregistrer un repas dans le journal nutrition. \u00c0 utiliser uniquement quand l'utilisateur annonce ce qu'il a mang\u00e9 ou bu, avec une quantit\u00e9 exploitable. Estimer calories et macros \u00e0 partir de sa description. Ne pas utiliser pour une question sur l'entra\u00eenement."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "365eec2a-676b-4410-b8a5-6747112f6a3d",
      "name": "Read today meals",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        2336,
        512
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $('Normalize user message').item.json.chat_id }}",
              "lookupColumn": "id_telegram"
            },
            {
              "lookupValue": "={{ $('Normalize user message').item.json.current_date }}",
              "lookupColumn": "date"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "nutrition"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "AI fitness coach data"
        },
        "descriptionType": "manual",
        "toolDescription": "Utile pour lire les repas du jour enregistr\u00e9s dans le journal nutrition. \u00c0 appeler quand l'utilisateur demande un bilan ou un total de ce qu'il a mang\u00e9 (calories, prot\u00e9ines, lipides, glucides). Additionner les lignes pour calculer le total de la journ\u00e9e."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "b10ef81e-b209-4408-98ce-1833fb5e21db",
      "name": "Save weekly nutrition plan",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        2480,
        512
      ],
      "parameters": {
        "columns": {
          "value": {
            "date_maj": "={{ $('Normalize user message').item.json.current_date }}",
            "plan_repas": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('plan_repas', 'Plan de repas de la semaine en texte clair et structur\u00e9') }}",
            "id_telegram": "={{ $('Normalize user message').item.json.chat_id }}",
            "liste_courses": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('liste_courses', 'Liste de courses regroup\u00e9e par cat\u00e9gorie en texte clair') }}"
          },
          "schema": [
            {
              "id": "id_telegram",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "id_telegram",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "date_maj",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "date_maj",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "plan_repas",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "plan_repas",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "liste_courses",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "liste_courses",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id_telegram"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "plan_nutrition"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "AI fitness coach data"
        },
        "descriptionType": "manual",
        "toolDescription": "Utile pour cr\u00e9er ou mettre \u00e0 jour le plan nutritionnel de la semaine et la liste de courses. \u00c0 utiliser quand l'utilisateur demande un nouveau plan ou une modification. Le nouveau plan REMPLACE le pr\u00e9c\u00e9dent. NE PAS utiliser pour enregistrer un repas mang\u00e9, c'est le r\u00f4le de Log meal in nutrition journal."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "d4f50ca9-5754-4c10-a77c-ef866ea5f797",
      "name": "Save weekly training plan",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        2640,
        512
      ],
      "parameters": {
        "columns": {
          "value": {
            "date_maj": "={{ $('Normalize user message').item.json.current_date }}",
            "id_telegram": "={{ $('Normalize user message').item.json.chat_id }}",
            "programme_texte": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('programme_texte', 'Programme de la semaine en texte clair: jours, exercices, s\u00e9ries, r\u00e9p\u00e9titions, repos') }}"
          },
          "schema": [
            {
              "id": "id_telegram",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "id_telegram",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "date_maj",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "date_maj",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "programme_texte",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "programme_texte",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id_telegram"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "plan_sport"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "AI fitness coach data"
        },
        "descriptionType": "manual",
        "toolDescription": "Utile pour cr\u00e9er ou mettre \u00e0 jour le programme d'entra\u00eenement de la semaine. \u00c0 utiliser quand l'utilisateur demande un nouveau programme sportif ou une modification. Le nouveau programme REMPLACE le pr\u00e9c\u00e9dent. NE PAS utiliser pour enregistrer une s\u00e9ance r\u00e9alis\u00e9e."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "da484017-74cc-41c3-a630-b9a93d62b17c",
      "name": "Read weekly training plan",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        2816,
        512
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $('Normalize user message').item.json.chat_id }}",
              "lookupColumn": "id_telegram"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "plan_sport"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "AI fitness coach data"
        },
        "descriptionType": "manual",
        "toolDescription": "Permet de lire le programme d'entra\u00eenement de la semaine de l'utilisateur. \u00c0 utiliser quand il demande son programme, ce qu'il doit faire aujourd'hui ou un jour pr\u00e9cis. NE PAS utiliser pour modifier le programme, c'est le r\u00f4le de Save weekly training plan."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "10afcbb4-3e18-492c-9eb2-c66e7a758e44",
      "name": "Create workout event in Calendar",
      "type": "n8n-nodes-base.googleCalendarTool",
      "position": [
        2976,
        512
      ],
      "parameters": {
        "end": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('end_time', 'Date et heure de fin au format ISO 8601 AAAA-MM-JJTHH:MM:SS') }}",
        "start": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('start_time', 'Date et heure de d\u00e9but au format ISO 8601 AAAA-MM-JJTHH:MM:SS, exemple 2026-07-15T18:00:00') }}",
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "descriptionType": "manual",
        "toolDescription": "Cr\u00e9e un \u00e9v\u00e9nement dans l'agenda de l'utilisateur pour programmer une s\u00e9ance de sport. \u00c0 utiliser quand il demande de planifier une s\u00e9ance. Calculer la date \u00e0 partir de la date du jour fournie dans le contexte.",
        "additionalFields": {
          "summary": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('titre', 'Titre de la s\u00e9ance, exemple: S\u00e9ance jambes') }}"
        }
      },
      "credentials": {
        "googleCalendarOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "b823d32a-9159-484b-bd07-01a71f443d41",
      "name": "Send coach reply on Telegram",
      "type": "n8n-nodes-base.telegram",
      "position": [
        2768,
        64
      ],
      "parameters": {
        "text": "={{ $json.output }}",
        "chatId": "={{ $('Normalize user message').item.json.chat_id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "1b74b581-204c-4d6c-82ee-d225903def0c",
      "name": "Sticky Note b72ab057",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -688,
        -96
      ],
      "parameters": {
        "width": 560,
        "height": 1956,
        "content": "# Coach fitness and nutrition on Telegram with Claude, Google Sheets and Calendar\n\n# \ud83d\udce5  [Open full documentation on Notion](https://automatisation.notion.site/Coach-fitness-and-nutrition-on-Telegram-with-Claude-Google-Sheets-and-Calendar-Course-support-En-3993d6550fd9810c9641ffc68da1d2aa)\n\n## How it works\n1. The workflow triggers when a Telegram message arrives (text or voice note).\n2. Voice notes are downloaded from Telegram and transcribed with OpenAI.\n3. The message, chat ID and current date are normalized into common fields.\n4. An AI coach agent (Anthropic Claude) with session memory answers in French and decides when to call its tools.\n5. Google Sheets tools read and write the user profile, workout history, nutrition journal and weekly plans.\n6. A Google Calendar tool schedules workout sessions on request.\n7. The coach reply is sent back to the user on Telegram.\n\n## Setup\n1. Connect your Telegram bot credential on the trigger, download and reply nodes.\n2. Connect Anthropic (chat model) and OpenAI (voice transcription) credentials.\n3. Connect Google Sheets OAuth2 and Google Calendar OAuth2 credentials.\n4. Create one Google Spreadsheet with 5 tabs: profil (id_telegram, poids_actuel, objectif), historique (id_telegram, date, exercice, performance), nutrition (id_telegram, date, repas, calories, proteines, lipides, glucides), plan_nutrition (id_telegram, date_maj, plan_repas, liste_courses), plan_sport (id_telegram, date_maj, programme_texte).\n5. Select this spreadsheet in every Google Sheets tool node and pick your calendar in the Calendar tool.\n6. Adjust the variables in the Configuration node (language, date format, memory length).\n\n## Requirements\n- A Telegram bot token (create one with @BotFather).\n- An Anthropic API key for the coach model.\n- An OpenAI API key for audio transcription.\n- A Google account with Sheets and Calendar access.\n\n## Customization\n- Edit the system prompt of the AI fitness coach agent to change the coaching style.\n- Change the language, date format or memory window in the Configuration node.\n- Swap the Anthropic model for another chat model, or add more Google Sheets tools (measurements, sleep, hydration).\n- Add a text-to-speech step to reply with voice notes.\n\n## Need help customizing?\nContact me for consulting and support : [Linkedin](https://www.linkedin.com/in/doctor-firass/)\n\n# MY NEW YOUTUBE CHANNEL\n\ud83d\udc49 [Subscribe to my new YouTube channel](https://www.youtube.com/@DrFiras_AI). Here I'll share videos and Shorts with practical tutorials and FREE templates for n8n.\n\n[![The AI Doctor](https://www.dr-firas.com/the-ai-doctor.png)](https://www.youtube.com/@DrFiras_AI)"
      },
      "typeVersion": 1
    },
    {
      "id": "83cde8f1-8366-43b8-8013-3935015ceae9",
      "name": "Sticky Note 33437496",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -64,
        -96
      ],
      "parameters": {
        "color": 7,
        "width": 656,
        "height": 400,
        "content": "## Receive and route messages\nReceives Telegram messages and checks whether the user sent a voice note or a text message. The Configuration node centralizes every user-adjustable variable: set your language, date format and memory length here."
      },
      "typeVersion": 1
    },
    {
      "id": "45cd71c5-61fc-485a-89b9-523906f9926a",
      "name": "Sticky Note ba9c6b3b",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        608,
        -96
      ],
      "parameters": {
        "color": 7,
        "width": 816,
        "height": 400,
        "content": "## Transcribe voice notes\nDownloads the Telegram voice note and transcribes it with OpenAI, then structures the transcript or the raw text into common fields (user_message, chat_id, current_date, weekday)."
      },
      "typeVersion": 1
    },
    {
      "id": "ee9be27c-c1f8-47c2-9bd2-f088714742bb",
      "name": "Sticky Note d7a975cd",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1664,
        -96
      ],
      "parameters": {
        "color": 7,
        "width": 976,
        "height": 400,
        "content": "## Run the AI coach agent\nThe central Claude agent with session memory interprets the request, applies the coaching rules and calls the right tool: profile, workout history, nutrition journal, weekly plans or calendar."
      },
      "typeVersion": 1
    },
    {
      "id": "4493e4c1-e8b3-4b6c-b661-f4809050078e",
      "name": "Sticky Note e7250f27",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1120,
        672
      ],
      "parameters": {
        "color": 7,
        "width": 1984,
        "content": "## Manage fitness records in Google Sheets\nTools used by the agent to read and write the profile, log workouts and meals, compute daily nutrition totals and store the weekly training and nutrition plans. The Calendar tool schedules workout sessions."
      },
      "typeVersion": 1
    },
    {
      "id": "6206bd29-6b78-45c6-b239-145cbc506952",
      "name": "Sticky Note f78a52ac",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2656,
        -96
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 400,
        "content": "## Send the reply\nSends the coach answer back to the user in the same Telegram chat."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": true,
    "executionOrder": "v1"
  },
  "versionId": "05d5e2b0-7bd3-434a-92ab-4c7e27a1651c",
  "nodeGroups": [],
  "connections": {
    "Configuration": {
      "main": [
        [
          {
            "node": "Check for voice message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Session memory": {
      "ai_memory": [
        [
          {
            "node": "AI fitness coach agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Read today meals": {
      "ai_tool": [
        [
          {
            "node": "AI fitness coach agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Claude chat model": {
      "ai_languageModel": [
        [
          {
            "node": "AI fitness coach agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Read user profile": {
      "ai_tool": [
        [
          {
            "node": "AI fitness coach agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Log workout session": {
      "ai_tool": [
        [
          {
            "node": "AI fitness coach agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Update user profile": {
      "ai_tool": [
        [
          {
            "node": "AI fitness coach agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Read workout history": {
      "ai_tool": [
        [
          {
            "node": "AI fitness coach agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "AI fitness coach agent": {
      "main": [
        [
          {
            "node": "Send coach reply on Telegram",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download voice message": {
      "main": [
        [
          {
            "node": "Transcribe voice with OpenAI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize user message": {
      "main": [
        [
          {
            "node": "AI fitness coach agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check for voice message": {
      "main": [
        [
          {
            "node": "Download voice message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Normalize user message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive Telegram message": {
      "main": [
        [
          {
            "node": "Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read weekly training plan": {
      "ai_tool": [
        [
          {
            "node": "AI fitness coach agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Save weekly training plan": {
      "ai_tool": [
        [
          {
            "node": "AI fitness coach agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Save weekly nutrition plan": {
      "ai_tool": [
        [
          {
            "node": "AI fitness coach agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Transcribe voice with OpenAI": {
      "main": [
        [
          {
            "node": "Normalize user message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log meal in nutrition journal": {
      "ai_tool": [
        [
          {
            "node": "AI fitness coach agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Create workout event in Calendar": {
      "ai_tool": [
        [
          {
            "node": "AI fitness coach agent",
            "type": "ai_tool",
            "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 turns a Telegram bot into a fitness and nutrition coach powered by Anthropic Claude, with voice-note transcription via OpenAI, user data stored in Google Sheets, and optional workout scheduling in Google Calendar. Triggers when a new Telegram message arrives in…

Source: https://n8n.io/workflows/16969/ — 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

Telegram Trigger receives incoming messages (text, voice, photo, document). Switch routes by message type to appropriate processors: Text → forwarded as-is. Voice → downloaded and sent to Transcribe a

Memory Buffer Window, Telegram Trigger, Telegram +12
AI & RAG

Transform your Telegram messenger into a powerful, multi-modal personal or team assistant. This n8n workflow creates an intelligent agent that can understand text, voice, images, and documents, and ta

Memory Buffer Window, Telegram Trigger, Telegram +10
AI & RAG

Personal Assistant. Uses memoryBufferWindow, agent, agentTool, httpRequestTool. Event-driven trigger; 77 nodes.

Memory Buffer Window, Agent, Agent Tool +15
AI & RAG

Jarvis is a powerful multi-agent productivity assistant built in n8n. It works directly from Telegram and can understand both text messages and voice notes.

Telegram Trigger, Telegram, OpenAI +10
AI & RAG

Inbox Guardian. Uses gmailTrigger, lmChatOpenAi, agent, textClassifier. Event-driven trigger; 66 nodes.

Gmail Trigger, OpenAI Chat, Agent +12