AutomationFlowsAI & RAG › Generate Weekly Habit and Mood Insights with Google Sheets and Openai

Generate Weekly Habit and Mood Insights with Google Sheets and Openai

ByPratistha Thapa @missylearnsai on n8n.io

Track daily mood, energy, sleep, stress, focus, and habits with a simple form, then receive a weekly AI-generated personal analytics report with patterns, best/hardest day comparison, and one small experiment for the next week. The result helps users understand what conditions…

Event trigger★★★★★ complexityAI-powered35 nodesGoogle SheetsForm TriggerGmailChain LlmOpenAI Chat
AI & RAG Trigger: Event Nodes: 35 Complexity: ★★★★★ AI nodes: yes Added:

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

This workflow follows the Chainllm → Form 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
{
  "id": "D6P8KczXKs1iN6US",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Habit & Mood Analytics Journal",
  "tags": [],
  "nodes": [
    {
      "id": "6818ef82-bd20-440d-b682-6dff01ba6d2b",
      "name": "Normalize Answers",
      "type": "n8n-nodes-base.set",
      "position": [
        144,
        16
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "b0c67b2c-d4cb-4663-bd07-abfee68887f2",
              "name": "Mood",
              "type": "string",
              "value": "={{ $json.Mood }}"
            },
            {
              "id": "3b0df9c7-ae33-4b57-9f3f-bdb670893cf9",
              "name": "Energy",
              "type": "string",
              "value": "={{ $json.Energy }}"
            },
            {
              "id": "da139efd-1318-45c1-9561-990d08fe066a",
              "name": "Stress",
              "type": "string",
              "value": "={{ $json.Stress }}"
            },
            {
              "id": "63d7637a-cbcb-461f-899f-f9a74f3a9e6f",
              "name": "Focus",
              "type": "string",
              "value": "={{ $json.Focus }}"
            },
            {
              "id": "6facaf24-2243-46c7-a936-357924a56d61",
              "name": "Sleep Hours",
              "type": "number",
              "value": "={{ $json['Sleep Hours'] }}"
            },
            {
              "id": "2866787a-4571-49bb-a91d-429cf104684e",
              "name": "Sleep Quality",
              "type": "string",
              "value": "={{ $json['Sleep Quality'] }}"
            },
            {
              "id": "23ab86c4-66cb-41bb-a347-32f67260f41f",
              "name": "Exercise Minutes",
              "type": "number",
              "value": "={{ $json['Exercise Minutes'] }}"
            },
            {
              "id": "04eb0eef-74ae-456f-9e84-e4776062b0e5",
              "name": "Meditation",
              "type": "string",
              "value": "={{ $json.Meditation }}"
            },
            {
              "id": "d89a0dde-92ee-4fae-8dc5-1f07badab434",
              "name": "Deep Work Hours",
              "type": "number",
              "value": "={{ $json['Deep Work Hours'] }}"
            },
            {
              "id": "02d1b8ce-5c56-492f-b2e7-0a496b461909",
              "name": "Social Connection",
              "type": "string",
              "value": "={{ $json['Social Connection'] }}"
            },
            {
              "id": "7f38e7ff-a04f-4188-a6c9-1294ad46a9ad",
              "name": "Screen Time",
              "type": "number",
              "value": "={{ $json['Screen Time'] }}"
            },
            {
              "id": "ebc1b10c-1ce9-4135-88a5-763f03d33213",
              "name": "Alcohol",
              "type": "string",
              "value": "={{ $json.Alcohol }}"
            },
            {
              "id": "32aca885-59ae-42ab-8c10-bbde18ab0941",
              "name": "Main Note",
              "type": "string",
              "value": "={{ $json['Main Note'] }}"
            },
            {
              "id": "c3ca97f7-bcb1-4758-9d72-7862b2655620",
              "name": "Gratitude / Win",
              "type": "string",
              "value": "={{ $json['Gratitude / Win'] }}"
            },
            {
              "id": "00789b29-4bfc-44a2-962b-93caca49ed4f",
              "name": "submittedAt",
              "type": "string",
              "value": "={{ DateTime.fromISO($json.submittedAt).toISODate() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "a5a9ad3f-1f8d-42f4-be48-a1885b76f3c5",
      "name": "Calculate Daily Scores",
      "type": "n8n-nodes-base.code",
      "position": [
        528,
        16
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\n\nfunction toNumber(value, fallback = 0) {\n  if (value === undefined || value === null || value === '') return fallback;\n  const num = Number(value);\n  return Number.isFinite(num) ? num : fallback;\n}\n\nfunction clamp(value, min, max) {\n  return Math.min(max, Math.max(min, value));\n}\n\nfunction answered(value) {\n  return value !== undefined && value !== null && String(value).trim() !== '';\n}\n\nfunction yes(value) {\n  if (value === true) return true;\n\n  const v = String(value ?? '').trim().toLowerCase();\n\n  return ['yes', 'y', 'true', '1', 'done', 'completed'].includes(v);\n}\n\nfunction normalize1to10(value) {\n  const n = clamp(toNumber(value, 5), 1, 10);\n  return (n - 1) / 9;\n}\n\nfunction band(score) {\n  if (score >= 75) return 'high';\n  if (score >= 55) return 'medium';\n  return 'low';\n}\n\nfunction getTodayYMD() {\n  return new Date().toISOString().slice(0, 10);\n}\n\nreturn items.map((item, index) => {\n  const data = item.json;\n\n  const mood = clamp(toNumber(data.mood, 5), 1, 10);\n  const energy = clamp(toNumber(data.energy, 5), 1, 10);\n  const stress = clamp(toNumber(data.stress, 5), 1, 10);\n  const focus = clamp(toNumber(data.focus, 5), 1, 10);\n  const sleepQuality = clamp(toNumber(data.sleep_quality, 5), 1, 10);\n  const socialConnection = clamp(toNumber(data.social_connection, 5), 1, 10);\n\n  const sleepHours = toNumber(data.sleep_hours, 0);\n  const exerciseMinutes = toNumber(data.exercise_minutes, 0);\n  const deepWorkHours = toNumber(data.deep_work_hours, 0);\n  const screenTimeHours = toNumber(data.screen_time_hours, 0);\n\n  const meditation = yes(data.meditation);\n\n  const caffeineAnswered = answered(data.caffeine_after_2pm);\n  const alcoholAnswered = answered(data.alcohol);\n\n  const caffeineAfter2pm = caffeineAnswered ? yes(data.caffeine_after_2pm) : false;\n  const alcohol = alcoholAnswered ? yes(data.alcohol) : false;\n\n  const noLateCaffeine = caffeineAnswered ? !caffeineAfter2pm : false;\n  const noAlcohol = alcoholAnswered ? !alcohol : false;\n\n  // Wellbeing score: state-based score, 0\u2013100.\n  const moodN = normalize1to10(mood);\n  const energyN = normalize1to10(energy);\n  const focusN = normalize1to10(focus);\n  const sleepQualityN = normalize1to10(sleepQuality);\n  const socialN = normalize1to10(socialConnection);\n\n  // Stress is reversed: lower stress is better.\n  const stressN = (10 - stress) / 9;\n\n  const wellbeingScore = Math.round(\n    100 * (\n      moodN * 0.30 +\n      energyN * 0.20 +\n      focusN * 0.15 +\n      sleepQualityN * 0.15 +\n      socialN * 0.10 +\n      stressN * 0.10\n    )\n  );\n\n  // Habit score: behavior-based score, 0\u2013100.\n  let habitScore = 0;\n\n  if (exerciseMinutes >= 20) {\n    habitScore += 20;\n  } else if (exerciseMinutes >= 10) {\n    habitScore += 10;\n  }\n\n  if (meditation) {\n    habitScore += 15;\n  }\n\n  if (sleepHours >= 7 && sleepHours <= 9) {\n    habitScore += 20;\n  } else if ((sleepHours >= 6 && sleepHours < 7) || (sleepHours > 9 && sleepHours <= 10)) {\n    habitScore += 10;\n  }\n\n  if (deepWorkHours >= 2) {\n    habitScore += 20;\n  } else if (deepWorkHours >= 1) {\n    habitScore += 10;\n  }\n\n  if (noLateCaffeine) {\n    habitScore += 10;\n  }\n\n  if (noAlcohol) {\n    habitScore += 15;\n  }\n\n  const tags = [];\n\n  if (mood >= 8) tags.push('high_mood');\n  if (mood <= 3) tags.push('low_mood');\n  if (energy >= 8) tags.push('high_energy');\n  if (energy <= 3) tags.push('low_energy');\n  if (stress >= 8) tags.push('high_stress');\n  if (sleepHours < 6) tags.push('low_sleep');\n  if (sleepHours >= 7 && sleepHours <= 9) tags.push('healthy_sleep');\n  if (exerciseMinutes >= 20) tags.push('exercise_20m');\n  if (meditation) tags.push('meditation');\n  if (deepWorkHours >= 2) tags.push('deep_work');\n  if (caffeineAfter2pm) tags.push('late_caffeine');\n  if (alcohol) tags.push('alcohol');\n\n  let riskFlag = 'normal';\n\n  if (mood <= 2 || stress >= 9) {\n    riskFlag = 'needs_support';\n  } else if (mood <= 4 || stress >= 8) {\n    riskFlag = 'watch';\n  }\n\n  let tinySuggestion = 'Repeat what worked today and keep the check-in habit going.';\n\n  if (sleepHours < 6.5) {\n    tinySuggestion = 'Prioritize recovery tonight. A simple sleep-focused evening may help tomorrow.';\n  } else if (stress >= 8) {\n    tinySuggestion = 'Plan one low-pressure recovery block tomorrow, even if it is only 15 minutes.';\n  } else if (exerciseMinutes < 20) {\n    tinySuggestion = 'Try a 20-minute walk or light movement session tomorrow.';\n  } else if (focus <= 4 && deepWorkHours < 1) {\n    tinySuggestion = 'Try one short uninterrupted focus block tomorrow before checking messages.';\n  } else if (socialConnection <= 4) {\n    tinySuggestion = 'Consider reaching out to one person tomorrow, even with a short message.';\n  }\n\n  const entryDate = data.date || getTodayYMD();\n\n  return {\n    json: {\n      ...data,\n\n      entry_id: data.entry_id || `entry_${Date.now()}_${index}_${Math.random().toString(36).slice(2, 8)}`,\n      date: String(entryDate).slice(0, 10),\n      created_at: data.created_at || new Date().toISOString(),\n\n      mood,\n      energy,\n      stress,\n      focus,\n      sleep_hours: sleepHours,\n      sleep_quality: sleepQuality,\n      exercise_minutes: exerciseMinutes,\n      meditation,\n      deep_work_hours: deepWorkHours,\n      social_connection: socialConnection,\n      screen_time_hours: screenTimeHours,\n      caffeine_after_2pm: caffeineAfter2pm,\n      alcohol,\n\n      note: data.note || '',\n      gratitude: data.gratitude || '',\n\n      wellbeing_score: wellbeingScore,\n      wellbeing_band: band(wellbeingScore),\n      habit_score: habitScore,\n      habit_band: band(habitScore),\n      risk_flag: riskFlag,\n      tags: tags.join(', '),\n      tiny_suggestion: tinySuggestion\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "c483d83f-40cf-4e4d-8ca3-29f8fdfffb10",
      "name": "Append Daily Entry",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        928,
        16
      ],
      "parameters": {
        "columns": {
          "value": {
            "date": "={{ $json.date }}",
            "mood": "={{ $json.mood }}",
            "note": "={{ $json.note }}",
            "tags": "={{ $json.tags }}",
            "focus": "={{ $json.focus }}",
            "energy": "={{ $json.energy }}",
            "stress": "={{ $json.stress }}",
            "alcohol": "={{ $json.alcohol }}",
            "entry_id": "={{ $json.entry_id }}",
            "gratitude": "={{ $json.gratitude }}",
            "risk_flag": "={{ $json.risk_flag }}",
            "created_at": "={{ $json.created_at }}",
            "habit_band": "={{ $json.habit_band }}",
            "meditation": "={{ $json.meditation }}",
            "habit_score": "={{ $json.habit_score }}",
            "sleep_hours": "={{ $json.sleep_hours }}",
            "sleep_quality": "={{ $json.sleep_quality }}",
            "wellbeing_band": "={{ $json.wellbeing_band }}",
            "deep_work_hours": "={{ $json.deep_work_hours }}",
            "tiny_suggestion": "={{ $json.tiny_suggestion }}",
            "wellbeing_score": "={{ $json.wellbeing_score }}",
            "exercise_minutes": "={{ $json.exercise_minutes }}",
            "screen_time_hours": "={{ $json.screen_time_hours }}",
            "social_connection": "={{ $json.social_connection }}",
            "caffeine_after_2pm": "={{ $json.caffeine_after_2pm }}"
          },
          "schema": [
            {
              "id": "entry_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "entry_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "created_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "mood",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "mood",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "energy",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "energy",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "stress",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "stress",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "focus",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "focus",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "sleep_hours",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "sleep_hours",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "sleep_quality",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "sleep_quality",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "exercise_minutes",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "exercise_minutes",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "meditation",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "meditation",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "deep_work_hours",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "deep_work_hours",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "social_connection",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "social_connection",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "screen_time_hours",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "screen_time_hours",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "caffeine_after_2pm",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "caffeine_after_2pm",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "alcohol",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "alcohol",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "note",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "note",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "gratitude",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "gratitude",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "wellbeing_score",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "wellbeing_score",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "wellbeing_band",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "wellbeing_band",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "habit_score",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "habit_score",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "habit_band",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "habit_band",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "risk_flag",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "risk_flag",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "tags",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "tags",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "tiny_suggestion",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "tiny_suggestion",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID_PLACEHOLDER/edit#gid=0",
          "cachedResultName": "daily_entries"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_GOOGLE_SHEET_ID_PLACEHOLDER",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID_PLACEHOLDER/edit?usp=drivesdk",
          "cachedResultName": "Habit & Mood Analytics"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "a0960cf6-f092-45be-b937-c5c4ed139541",
      "name": "On form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -112,
        16
      ],
      "parameters": {
        "options": {},
        "formTitle": "Daily Check In",
        "formFields": {
          "values": [
            {
              "fieldType": "dropdown",
              "fieldLabel": "Mood",
              "fieldOptions": {
                "values": [
                  {
                    "option": "1"
                  },
                  {
                    "option": "2"
                  },
                  {
                    "option": "3"
                  },
                  {
                    "option": "4"
                  },
                  {
                    "option": "5"
                  },
                  {
                    "option": "6"
                  },
                  {
                    "option": "7"
                  },
                  {
                    "option": "8"
                  },
                  {
                    "option": "9"
                  },
                  {
                    "option": "10"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "Energy",
              "fieldOptions": {
                "values": [
                  {
                    "option": "1"
                  },
                  {
                    "option": "2"
                  },
                  {
                    "option": "3"
                  },
                  {
                    "option": "4"
                  },
                  {
                    "option": "5"
                  },
                  {
                    "option": "6"
                  },
                  {
                    "option": "7"
                  },
                  {
                    "option": "8"
                  },
                  {
                    "option": "9"
                  },
                  {
                    "option": "10"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "Stress",
              "fieldOptions": {
                "values": [
                  {
                    "option": "1"
                  },
                  {
                    "option": "2"
                  },
                  {
                    "option": "3"
                  },
                  {
                    "option": "4"
                  },
                  {
                    "option": "5"
                  },
                  {
                    "option": "6"
                  },
                  {
                    "option": "7"
                  },
                  {
                    "option": "8"
                  },
                  {
                    "option": "9"
                  },
                  {
                    "option": "10"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "Focus",
              "fieldOptions": {
                "values": [
                  {
                    "option": "1"
                  },
                  {
                    "option": "2"
                  },
                  {
                    "option": "3"
                  },
                  {
                    "option": "4"
                  },
                  {
                    "option": "5"
                  },
                  {
                    "option": "6"
                  },
                  {
                    "option": "7"
                  },
                  {
                    "option": "8"
                  },
                  {
                    "option": "9"
                  },
                  {
                    "option": "10"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "number",
              "fieldLabel": "Sleep Hours",
              "requiredField": true
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "Sleep Quality",
              "fieldOptions": {
                "values": [
                  {
                    "option": "1"
                  },
                  {
                    "option": "2"
                  },
                  {
                    "option": "3"
                  },
                  {
                    "option": "4"
                  },
                  {
                    "option": "5"
                  },
                  {
                    "option": "6"
                  },
                  {
                    "option": "7"
                  },
                  {
                    "option": "8"
                  },
                  {
                    "option": "9"
                  },
                  {
                    "option": "10"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "number",
              "fieldLabel": "Exercise Minutes",
              "requiredField": true
            },
            {
              "fieldType": "radio",
              "fieldLabel": "Meditation",
              "fieldOptions": {
                "values": [
                  {
                    "option": "Yes"
                  },
                  {
                    "option": "No"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "number",
              "fieldLabel": "Deep Work Hours",
              "requiredField": true
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "Social Connection",
              "fieldOptions": {
                "values": [
                  {
                    "option": "1"
                  },
                  {
                    "option": "2"
                  },
                  {
                    "option": "3"
                  },
                  {
                    "option": "4"
                  },
                  {
                    "option": "5"
                  },
                  {
                    "option": "6"
                  },
                  {
                    "option": "7"
                  },
                  {
                    "option": "8"
                  },
                  {
                    "option": "9"
                  },
                  {
                    "option": "10"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "number",
              "fieldLabel": "Screen Time",
              "requiredField": true
            },
            {
              "fieldType": "radio",
              "fieldLabel": "Caffeine after 2PM",
              "fieldOptions": {
                "values": [
                  {
                    "option": "Yes"
                  },
                  {
                    "option": "No"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "radio",
              "fieldLabel": "Alcohol",
              "fieldOptions": {
                "values": [
                  {
                    "option": "Yes"
                  },
                  {
                    "option": "No"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "textarea",
              "fieldLabel": "Main Note"
            },
            {
              "fieldType": "textarea",
              "fieldLabel": "Gratitude / Win"
            }
          ]
        },
        "formDescription": "Let us know how you feel today!"
      },
      "typeVersion": 2.5
    },
    {
      "id": "31f4654d-21dd-4321-9ebb-dfb733735a5d",
      "name": "Send Supportive Confirmation",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1584,
        -224
      ],
      "parameters": {
        "sendTo": "YOUR_EMAIL_ADDRESS_PLACEHOLDER",
        "message": "=Your check-in has been saved.  I\u2019m sorry today felt heavy.  Today\u2019s wellbeing score: {{ $json.wellbeing_score }}/100 Habit score: {{ $json.habit_score }}/100  A gentle next step: {{ $json.tiny_suggestion }}  Consider reaching out to someone you trust. If you feel unsafe or at risk of harm, contact local emergency or crisis support.  This journal is for personal reflection only and is not medical advice.",
        "options": {},
        "subject": "Daily Check In Confirmation",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "0bdfe896-034c-4daa-a777-f4344c975b05",
      "name": "Send Normal Confirmation",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1568,
        -16
      ],
      "parameters": {
        "sendTo": "YOUR_EMAIL_ADDRESS_PLACEHOLDER",
        "message": "=\u2705 Check-in saved.\n\nWellbeing score: {{ $json.wellbeing_score }}/100\nHabit score: {{ $json.habit_score }}/100\n\nToday\u2019s tag summary:\n{{ $json.tags }}\n\nTiny suggestion:\n{{ $json.tiny_suggestion }}",
        "options": {},
        "subject": "Daily Check In Confirmation",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "af5ee9db-c85a-462e-a082-4718d437f4c1",
      "name": "Weekly Report Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -160,
        912
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 9
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "38e4e8f9-5199-407d-a9b9-5af3173a4d2b",
      "name": "Get Daily Entries",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        96,
        912
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID_PLACEHOLDER/edit#gid=0",
          "cachedResultName": "daily_entries"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_GOOGLE_SHEET_ID_PLACEHOLDER",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID_PLACEHOLDER/edit?usp=drivesdk",
          "cachedResultName": "Habit & Mood Analytics"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "bcc5c4cb-5d18-4c9e-bcd6-a8475303700d",
      "name": "Calculate Weekly Analytics",
      "type": "n8n-nodes-base.code",
      "position": [
        544,
        912
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\n\nconst MIN_ENTRIES = 3;\n\nfunction toNumber(value, fallback = null) {\n  if (value === undefined || value === null || value === '') return fallback;\n  const num = Number(value);\n  return Number.isFinite(num) ? num : fallback;\n}\n\nfunction yes(value) {\n  if (value === true) return true;\n\n  const v = String(value ?? '').trim().toLowerCase();\n\n  return ['yes', 'y', 'true', '1', 'done', 'completed'].includes(v);\n}\n\nfunction ymdFrom(value) {\n  if (!value) return null;\n\n  const s = String(value).trim();\n\n  if (/^\\d{4}-\\d{2}-\\d{2}/.test(s)) {\n    return s.slice(0, 10);\n  }\n\n  const d = new Date(s);\n\n  if (Number.isNaN(d.getTime())) return null;\n\n  return d.toISOString().slice(0, 10);\n}\n\nfunction toYMD(date) {\n  return date.toISOString().slice(0, 10);\n}\n\nfunction dayName(ymd) {\n  if (!ymd) return '';\n\n  const [year, month, day] = ymd.split('-').map(Number);\n  const d = new Date(Date.UTC(year, month - 1, day));\n\n  return d.toLocaleDateString('en-US', { weekday: 'long' });\n}\n\nfunction average(rows, field) {\n  const values = rows\n    .map(row => toNumber(row[field], null))\n    .filter(value => value !== null);\n\n  if (!values.length) return null;\n\n  const total = values.reduce((sum, value) => sum + value, 0);\n\n  return Number((total / values.length).toFixed(1));\n}\n\nfunction countWhere(rows, predicate) {\n  return rows.filter(predicate).length;\n}\n\nfunction comparePattern({\n  rows,\n  label,\n  metric,\n  positiveName,\n  negativeName,\n  predicate,\n  threshold = 0.7,\n  lowerIsBetter = false\n}) {\n  const positiveRows = rows.filter(predicate);\n  const negativeRows = rows.filter(row => !predicate(row));\n\n  if (positiveRows.length < 2 || negativeRows.length < 2) return null;\n\n  const positiveAvg = average(positiveRows, metric);\n  const negativeAvg = average(negativeRows, metric);\n\n  if (positiveAvg === null || negativeAvg === null) return null;\n\n  const diff = Number((positiveAvg - negativeAvg).toFixed(1));\n\n  if (Math.abs(diff) < threshold) return null;\n\n  if (lowerIsBetter) {\n    if (diff < 0) {\n      return `${label}: ${positiveName} days had lower ${metric.replaceAll('_', ' ')} (${positiveAvg}) than ${negativeName} days (${negativeAvg}).`;\n    }\n\n    return `${label}: ${positiveName} days had higher ${metric.replaceAll('_', ' ')} (${positiveAvg}) than ${negativeName} days (${negativeAvg}).`;\n  }\n\n  if (diff > 0) {\n    return `${label}: ${positiveName} days averaged higher ${metric.replaceAll('_', ' ')} (${positiveAvg}) than ${negativeName} days (${negativeAvg}).`;\n  }\n\n  return `${label}: ${positiveName} days averaged lower ${metric.replaceAll('_', ' ')} (${positiveAvg}) than ${negativeName} days (${negativeAvg}).`;\n}\n\n// Report the previous completed Monday\u2013Sunday calendar week.\n// Example:\n// If this runs on Monday 2026-05-25,\n// it reports Monday 2026-05-18 through Sunday 2026-05-24.\n\n// Use the workflow run date.\nconst runDate = new Date();\n\n// Normalize to UTC midnight for stable date math.\nconst runUTC = new Date(Date.UTC(\n  runDate.getUTCFullYear(),\n  runDate.getUTCMonth(),\n  runDate.getUTCDate()\n));\n\n// JavaScript getUTCDay():\n// Sunday = 0, Monday = 1, Tuesday = 2, ..., Saturday = 6\nconst dayOfWeek = runUTC.getUTCDay();\n\n// Days since the current week's Monday.\n// Monday -> 0\n// Tuesday -> 1\n// ...\n// Sunday -> 6\nconst daysSinceMonday = (dayOfWeek + 6) % 7;\n\n// Current week's Monday\nconst currentWeekMonday = new Date(runUTC);\ncurrentWeekMonday.setUTCDate(runUTC.getUTCDate() - daysSinceMonday);\n\n// Previous week's Monday\nconst startDate = new Date(currentWeekMonday);\nstartDate.setUTCDate(currentWeekMonday.getUTCDate() - 7);\n\n// Previous week's Sunday\nconst endDate = new Date(currentWeekMonday);\nendDate.setUTCDate(currentWeekMonday.getUTCDate() - 1);\n\nconst weekStart = toYMD(startDate);\nconst weekEnd = toYMD(endDate);\n\nconst allRows = items\n  .map(item => item.json)\n  .map(row => ({\n    ...row,\n    date: ymdFrom(row.date),\n    mood: toNumber(row.mood, null),\n    energy: toNumber(row.energy, null),\n    stress: toNumber(row.stress, null),\n    focus: toNumber(row.focus, null),\n    sleep_hours: toNumber(row.sleep_hours, null),\n    sleep_quality: toNumber(row.sleep_quality, null),\n    exercise_minutes: toNumber(row.exercise_minutes, 0),\n    deep_work_hours: toNumber(row.deep_work_hours, 0),\n    social_connection: toNumber(row.social_connection, null),\n    screen_time_hours: toNumber(row.screen_time_hours, null),\n    wellbeing_score: toNumber(row.wellbeing_score, null),\n    habit_score: toNumber(row.habit_score, null),\n    meditation: yes(row.meditation),\n    caffeine_after_2pm: yes(row.caffeine_after_2pm),\n    alcohol: yes(row.alcohol)\n  }))\n  .filter(row => row.date);\n\nconst weekRows = allRows\n  .filter(row => row.date >= weekStart && row.date <= weekEnd)\n  .sort((a, b) => a.date.localeCompare(b.date));\n\nconst entryCount = weekRows.length;\n\nconst bestRow = weekRows\n  .filter(row => row.wellbeing_score !== null)\n  .sort((a, b) => b.wellbeing_score - a.wellbeing_score)[0];\n\nconst hardestRow = weekRows\n  .filter(row => row.wellbeing_score !== null)\n  .sort((a, b) => a.wellbeing_score - b.wellbeing_score)[0];\n\nconst patterns = [\n  comparePattern({\n    rows: weekRows,\n    label: 'Exercise and mood',\n    metric: 'mood',\n    positiveName: 'exercise',\n    negativeName: 'non-exercise',\n    predicate: row => row.exercise_minutes >= 20\n  }),\n\n  comparePattern({\n    rows: weekRows,\n    label: 'Sleep and focus',\n    metric: 'focus',\n    positiveName: '7+ hour sleep',\n    negativeName: 'shorter sleep',\n    predicate: row => row.sleep_hours >= 7\n  }),\n\n  comparePattern({\n    rows: weekRows,\n    label: 'Meditation and stress',\n    metric: 'stress',\n    positiveName: 'meditation',\n    negativeName: 'non-meditation',\n    predicate: row => row.meditation,\n    lowerIsBetter: true\n  }),\n\n  comparePattern({\n    rows: weekRows,\n    label: 'Late caffeine and sleep quality',\n    metric: 'sleep_quality',\n    positiveName: 'no late caffeine',\n    negativeName: 'late caffeine',\n    predicate: row => !row.caffeine_after_2pm\n  }),\n\n  comparePattern({\n    rows: weekRows,\n    label: 'Deep work and focus',\n    metric: 'focus',\n    positiveName: '2+ hour deep work',\n    negativeName: 'lighter deep work',\n    predicate: row => row.deep_work_hours >= 2\n  })\n].filter(Boolean);\n\nconst notes = weekRows\n  .filter(row => row.note)\n  .map(row => `${row.date}: ${row.note}`);\n\nconst gratitudeWins = weekRows\n  .filter(row => row.gratitude)\n  .map(row => `${row.date}: ${row.gratitude}`);\n\nconst weeklyMetrics = {\n  avg_mood: average(weekRows, 'mood'),\n  avg_energy: average(weekRows, 'energy'),\n  avg_stress: average(weekRows, 'stress'),\n  avg_focus: average(weekRows, 'focus'),\n  avg_sleep_hours: average(weekRows, 'sleep_hours'),\n  avg_sleep_quality: average(weekRows, 'sleep_quality'),\n  avg_wellbeing_score: average(weekRows, 'wellbeing_score'),\n  avg_habit_score: average(weekRows, 'habit_score'),\n\n  exercise_days: countWhere(weekRows, row => row.exercise_minutes >= 20),\n  meditation_days: countWhere(weekRows, row => row.meditation),\n  deep_work_days: countWhere(weekRows, row => row.deep_work_hours >= 2),\n  no_late_caffeine_days: countWhere(weekRows, row => !row.caffeine_after_2pm),\n  no_alcohol_days: countWhere(weekRows, row => !row.alcohol)\n};\n\nconst bestDay = bestRow\n  ? `${dayName(bestRow.date)} (${bestRow.date}) \u2014 wellbeing ${bestRow.wellbeing_score}/100`\n  : '';\n\nconst hardestDay = hardestRow\n  ? `${dayName(hardestRow.date)} (${hardestRow.date}) \u2014 wellbeing ${hardestRow.wellbeing_score}/100`\n  : '';\n\nconst dailySnapshots = weekRows.map(row => ({\n  date: row.date,\n  day: dayName(row.date),\n  wellbeing_score: row.wellbeing_score,\n  habit_score: row.habit_score,\n  mood: row.mood,\n  energy: row.energy,\n  stress: row.stress,\n  focus: row.focus,\n  sleep_hours: row.sleep_hours,\n  sleep_quality: row.sleep_quality,\n  exercise_minutes: row.exercise_minutes,\n  meditation: row.meditation,\n  deep_work_hours: row.deep_work_hours,\n  social_connection: row.social_connection,\n  screen_time_hours: row.screen_time_hours,\n  caffeine_after_2pm: row.caffeine_after_2pm,\n  alcohol: row.alcohol,\n  note: row.note || '',\n  gratitude: row.gratitude || ''\n}));\n\nconst bestDaySnapshot = bestRow\n  ? dailySnapshots.find(day => day.date === bestRow.date)\n  : null;\n\nconst hardestDaySnapshot = hardestRow\n  ? dailySnapshots.find(day => day.date === hardestRow.date)\n  : null;\n\nreturn [\n  {\n    json: {\n      week_start: weekStart,\n      week_end: weekEnd,\n      entry_count: entryCount,\n      min_entries_required: MIN_ENTRIES,\n      enough_entries: entryCount >= MIN_ENTRIES,\n\n      ...weeklyMetrics,\n\n      best_day: bestDay,\n      hardest_day: hardestDay,\n\n      detected_patterns: patterns.join('\\n'),\n      detected_patterns_array: patterns,\n      daily_snapshots: dailySnapshots,\n      best_day_snapshot: bestDaySnapshot,\n      hardest_day_snapshot: hardestDaySnapshot,\n      notes,\n      gratitude_wins: gratitudeWins,\n\n      weekly_metrics: weeklyMetrics,\n\n      created_at: new Date().toISOString()\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "3aaed056-51c4-40aa-adf6-07b274c902ed",
      "name": "Enough Entries?",
      "type": "n8n-nodes-base.if",
      "position": [
        800,
        912
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5d4d4bf5-9739-4ec0-b4c7-763797740132",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.enough_entries }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "0e2f74de-1a54-4ef0-9d1c-9de97acbf2be",
      "name": "Basic LLM Chain",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        1296,
        800
      ],
      "parameters": {
        "text": "=You are a personal analytics coach for a habit and mood journal.\n\nYour job is to generate one useful weekly insight and one small experiment for next week.\n\nThe weekly scorecard is already visible in the email. Do not summarize it.\n\nYour response should feel grounded, warm, light, specific, practical, and non-judgmental.\n\nDo not sound like:\n- a therapist\n- a productivity guru\n- a generic wellness newsletter\n- a dashboard narrator\n\nUse only the data provided below. Do not invent causes, routines, emotions, events, schedules, or explanations.\n\nAllowed tracked habits and conditions:\nsleep duration, sleep quality, exercise/movement, meditation, deep work, focus, stress, mood, energy, social connection, screen time, caffeine after 2pm, alcohol.\n\nDo not recommend actions outside the allowed tracked habits and conditions.\n\nMAIN DECISION RULE:\nFirst decide whether this week has a support-stack contrast.\n\nA support is present when:\n- sleep_hours >= 7\n- sleep_quality >= 7\n- exercise_minutes >= 20\n- meditation is true\n- deep_work_hours >= 1\n- stress <= 5\n- focus >= 6\n- caffeine_after_2pm is false\n- alcohol is false\n\nCount supports for best_day_snapshot and hardest_day_snapshot.\n\nIf best_day_snapshot has 5 or more supports and hardest_day_snapshot has 3 or fewer supports:\n- The main insight MUST be support-stack contrast.\n- The headline MUST be about the best/hardest day contrast or support stack.\n- Do NOT make caffeine, sleep, exercise, meditation, or deep work alone the main headline.\n- Caffeine may be used as the watchout or experiment, but not as the main insight.\n- The core insight must compare the support stack on the best day with the support drop-off on the hardest day.\n\nIf the support-stack contrast rule is not met, choose one of these themes:\n1. Friction loop: one visible friction point seemed linked with another area.\n2. Recovery baseline: sleep, stress, or energy shaped several other signals.\n3. Single-habit hypothesis: one habit is the clearest signal.\n4. Low-data signal: too few entries or patterns to trust.\n\nHard grounding rules:\n- Do not use the word \"routine\" in the output.\n- Do not mention \"morning\" unless both the best day and hardest day explicitly mention morning.\n- Do not mention work schedule, meetings, commute, weekends, social plans, or self-care unless they appear in notes or daily snapshots.\n- Do not say something was missing from a day unless that day's snapshot explicitly shows it.\n- Do not tie caffeine, alcohol, sleep, exercise, meditation, or deep work to a specific day unless that day explicitly shows it.\n- Do not invent combined relationships. For example, do not say \"late caffeine on non-meditation days\" unless that exact relationship appears in the data.\n- Never imply that one week of data proves anything.\n\nAvoid these words and phrases in the output:\nbe mindful, finding balance, balanced approach, manage your time, productive tone, prioritize self-care, boost your mood, incorporate more, moving forward, preserve momentum, wellbeing resilience, cause, caused, led to, leading to, proves, explains, key, must, always, fix, failure, vulnerable, cure, contributed to, maintain, prioritize, overall wellbeing, supportive days.\n\nUse careful language:\nseemed linked, coincided with, is worth testing, may be worth preserving.\n\nHeadline rules:\n- Under 12 words.\n- Specific to this week's chosen theme.\n- Should sound like an observation from this user's week, not advice.\n- If support-stack contrast is selected, mention support stack or the best/hardest day contrast.\n- Do not say \"best days\" unless multiple best/strong days are being referenced.\n- Do not say \"better days\", \"productive mornings\", \"momentum\", \"balance\", \"resilience\", or \"overall wellbeing.\"\n\nCore insight rules:\n- Two concise sentences.\n- Explain the deeper weekly theme.\n- Do not summarize the scorecard.\n- Do not list several correlations.\n- If support-stack contrast is selected, compare best_day_snapshot and hardest_day_snapshot.\n- If support-stack contrast is selected, mention at least three support differences across the two days.\n- Do not reduce a support-stack insight to only sleep, caffeine, or exercise.\n- The insight should give the user a useful mental model, not just a fact.\n- Do not use causal language such as \"leading to\" or \"contributed to.\"\n\nLeverage point rules:\n- Say what to preserve, not what to achieve.\n- It can be one habit, one condition, or a small support stack.\n- It must connect directly to the chosen theme.\n- If support-stack contrast is selected, the leverage point should be the smallest repeatable support stack.\n- It should not ask the user to change more than two things.\n- It must not be identical to the experiment.\n- Avoid broad instructions like \"preserve sleep and avoid caffeine.\"\n\nWatchout rules:\n- Name one friction point from detected patterns, journal notes, or daily snapshots only.\n- Do not invent a cause.\n- Do not invent combined relationships.\n- If the detected pattern says \"late caffeine and sleep quality\", the watchout may mention late caffeine and sleep quality only.\n- Do not add stress, alcohol, meditation, or wellbeing unless the detected pattern explicitly supports that connection.\n- Do not make it sound alarming.\n\nExperiment rules:\n- The experiment must test either:\n  1. the watchout friction point, or\n  2. the smallest repeatable part of the chosen theme.\n- The experiment must use tracked habits only.\n- It must be one sentence string, not an object.\n- It must include behavior, duration, frequency, and comparison metric.\n- It should be doable on at least 3 or 4 days.\n- It should not require daily perfection.\n- It should take less than 45 minutes per day.\n- It should not require 2+ hours of deep work.\n- It should not require changing more than two behaviors.\n- It must connect clearly to the core insight or watchout.\n\nPreferred experiment patterns:\nIf the watchout is late caffeine, use:\n\"For 7 days, avoid caffeine after 2 PM on at least 4 days and compare sleep quality.\"\n\nIf the theme is movement and mood, use:\n\"For 7 days, do 20 minutes of movement on at least 4 days and compare mood.\"\n\nIf the theme is deep work and focus, use:\n\"For 7 days, complete one 30\u201345 minute deep work block on at least 4 days and compare focus.\"\n\nIf the theme is meditation and stress, use:\n\"For 7 days, meditate for 5\u201310 minutes on at least 4 days and compare stress.\"\n\nIf the theme is sleep and focus, use:\n\"For 7 days, aim for 7+ hours of sleep on at least 4 nights and compare focus.\"\n\nReflection question rules:\n- Ask about lived experience, not a calculation.\n- Do not ask the user to compare averages or scores that the workflow already calculated.\n- Reference a specific day, score, note, or contrast from the week.\n- Do not ask a yes/no question.\n- Do not ask the user to plan a new habit.\n- Do not ask how to apply something to a future day.\n- Do not use the word \"routine\".\n- If support-stack contrast is selected, compare concrete details from the best day and hardest day.\n\nWeekly data:\n\nWeek:\n{{ $json.week_start }} to {{ $json.week_end }}\n\nEntry count:\n{{ $json.entry_count }}\n\nBest day:\n{{ $json.best_day }}\n\nHardest day:\n{{ $json.hardest_day }}\n\nWeekly metrics:\n{{ JSON.stringify($json.weekly_metrics) }}\n\nBest day snapshot:\n{{ JSON.stringify($json.best_day_snapshot) }}\n\nHardest day snapshot:\n{{ JSON.stringify($json.hardest_day_snapshot) }}\n\nDetected patterns:\n{{ $json.detected_patterns }}\n\nJournal notes:\n{{ JSON.stringify($json.notes) }}\n\nGratitude/wins:\n{{ JSON.stringify($json.gratitude_wins) }}\n\nDaily snapshots:\n{{ JSON.stringify($json.daily_snapshots) }}\n\nFinal self-check before returning:\n- Did I count supports for best_day_snapshot and hardest_day_snapshot?\n- If best day has 5+ supports and hardest day has 3 or fewer, did I choose support-stack contrast?\n- Did I avoid making caffeine or sleep alone the main insight when support-stack contrast is stronger?\n- Do all fields align with the same theme?\n- Did I avoid invented details and invented combined relationships?\n- Is the insight a theme, not a list of correlations?\n- Does the experiment connect to the insight or watchout?\n- Is the experiment measurable, realistic, and one sentence?\n- Is the reflection question about lived experience, not math or planning?\n- Are all JSON values strings?\n- Is the output valid JSON only?\n\nReturn valid JSON only.\nDo not use Markdown.\nDo not include any text before or after the JSON.\n\nReturn exactly this object with string values only:\n\n{\n  \"headline\": \"A specific, non-generic headline under 12 words.\",\n  \"core_insight\": \"Two concise sentences explaining the deeper weekly theme. Not a scorecard summary.\",\n  \"leverage_point\": \"One habit, condition, or small support stack to preserve next week.\",\n  \"watchout\": \"One friction point from the data only. No invented causes.\",\n  \"next_experiment\": \"One measurable 7-day experiment in one sentence.\",\n  \"reflection_question\": \"One specific question referencing a score, day, note, or contrast from this week.\"\n}",
        "batching": {},
        "promptType": "define"
      },
      "typeVersion": 1.9
    },
    {
      "id": "2724da37-5c21-4130-94e3-41c01f1efd04",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1392,
        944
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "llama-3.1-8b-instant",
          "cachedResultName": "llama-3.1-8b-instant"
        },
        "options": {
          "maxTokens": 400,
          "temperature": 0.3
        },
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "9e79590c-2354-45b2-bc87-ac9d70e6006d",
      "name": "Send Not Enough Data Message",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1088,
        1168
      ],
      "parameters": {
        "sendTo": "YOUR_EMAIL_ADDRESS_PLACEHOLDER",
        "message": "=Not enough check-ins to generate a weekly report.  \nEntries found: {{ $json.entry_count }} \nMinimum required: {{ $json.min_entries_required }}  \n\nKeep logging and I\u2019ll generate insights once there is enough data.",
        "options": {},
        "subject": "=Just a few more check-ins needed for your weekly insights!"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "64b2e4e4-a954-4f82-a21d-a453356f46c3",
      "name": "Append Weekly Report",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2016,
        864
      ],
      "parameters": {
        "columns": {
          "value": {
            "avg_mood": "={{ $('Calculate Weekly Analytics').item.json.avg_mood }}",
            "best_day": "={{ $('Calculate Weekly Analytics').item.json.best_day }}",
            "week_end": "={{ $('Calculate Weekly Analytics').item.json.week_end }}",
            "avg_focus": "={{ $('Calculate Weekly Analytics').item.json.avg_focus }}",
            "ai_summary": "={{ $json.output || $json.text || $json.message?.content || $json.choices?.[0]?.message?.content }}",
            "avg_energy": "={{ $('Calculate Weekly Analytics').item.json.avg_energy }}",
            "avg_stress": "={{ $('Calculate Weekly Analytics').item.json.avg_stress }}",
            "created_at": "={{ $('Calculate Weekly Analytics').item.json.created_at }}",
            "week_start": "={{ $('Calculate Weekly Analytics').item.json.week_start }}",
            "entry_count": "={{ $('Calculate Weekly Analytics').item.json.entry_count }}",
            "hardest_day": "={{ $('Calculate Weekly Analytics').item.json.hardest_day }}",
            "avg_habit_score": "={{ $('Calculate Weekly Analytics').item.json.avg_habit_score }}",
            "avg_sleep_hours": "={{ $('Calculate Weekly Analytics').item.json.avg_sleep_hours }}",
            "avg_sleep_quality": "={{ $('Calculate Weekly Analytics').item.json.avg_sleep_quality }}",
            "detected_patterns": "={{ $('Calculate Weekly Analytics').item.json.detected_patterns }}",
            "avg_wellbeing_score": "={{ $('Calculate Weekly Analytics').item.json.avg_wellbeing_score }}"
          },
          "schema": [
            {
              "id": "week_start",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "week_start",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "week_end",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "week_end",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "entry_count",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "entry_count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "avg_mood",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "avg_mood",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "avg_energy",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "avg_energy",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "avg_stress",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "avg_stress",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "avg_focus",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "avg_focus",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "avg_sleep_hours",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "avg_sleep_hours",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "avg_sleep_quality",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "avg_sleep_quality",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "avg_wellbeing_score",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "avg_wellbeing_score",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "avg_habit_score",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "avg_habit_score",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "best_day",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "best_day",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "hardest_day",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "hardest_day",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "detected_patterns",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "detected_patterns",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ai_summary",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "ai_summary",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "created_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 361909476,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID_PLACEHOLDER/edit#gid=361909476",
          "cachedResultName": "weekly_reports"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_GOOGLE_SHEET_ID_PLACEHOLDER",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID_PLACEHOLDER/edit?usp=drivesdk",
          "cachedResultName": "Habit & Mood Analytics"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "d4a3ba07-9d26-415b-a02a-5a02f774c4ff",
      "name": "Email Weekly Insights",
      "type": "n8n-nodes-base.gmail",
      "posit

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

Track daily mood, energy, sleep, stress, focus, and habits with a simple form, then receive a weekly AI-generated personal analytics report with patterns, best/hardest day comparison, and one small experiment for the next week. The result helps users understand what conditions…

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

The workflow runs every hour with a randomized delay of 5–20 minutes to help distribute load. It records the exact date and time a lead is emailed so you can track outreach. Follow-ups are automatical

Google Sheets, Agent, OpenAI Chat +5
AI & RAG

This workflow is perfect for graphic designers, creative agencies, marketing teams, or freelancers who regularly use AI-generated images in their projects. It's specifically beneficial for teams that

Google Sheets, Google Drive, HTTP Request +5
AI & RAG

AI Agents Vs AI Workflow. Uses lmChatOpenAi, gmailTrigger, gmail, gmailTool. Event-driven trigger; 30 nodes.

OpenAI Chat, Gmail Trigger, Gmail +7
AI & RAG

It works with both Thai and English business cards and even includes an optional step to draft greeting emails automatically.

OpenAI Chat, Agent, Chain Llm +5
AI & RAG

This n8n template automates targeted lead discovery, AI-driven data structuring, and personalized cold-email sending at controlled intervals. It’s ideal for sales teams, founders, and agencies that wa

Google Sheets, Form Trigger, Chain Llm +6