{
  "nodes": [
    {
      "parameters": {
        "content": "# Contact Email Store\n\nStores email as .md file in contact's emails/ folder and updates README.md profile via LLM.\n\n**Inputs:**\n- emails_folder_id: Target folder for email storage\n- folder_id: Contact folder (for README)\n- email_subject, body_core: Email content\n- contact_name, contact_email: Contact info (the other party)",
        "height": 240,
        "width": 400
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4048,
        2944
      ],
      "typeVersion": 1,
      "id": "2f632337-594b-4058-ad9d-8bd231539a3c",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "inputSource": "passthrough"
      },
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.1,
      "position": [
        4528,
        2976
      ],
      "id": "37bcbe68-f8aa-4c80-a2bc-b74aeafb40ca",
      "name": "When Executed by Another Workflow"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        4528,
        2784
      ],
      "id": "134827e6-f9a5-43f9-a2b3-03fa2393cb04",
      "name": "Manual Trigger"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "emails-folder-id",
              "name": "emails_folder_id",
              "value": "={{ $json.emails_folder_id }}",
              "type": "string"
            },
            {
              "id": "folder-id",
              "name": "folder_id",
              "value": "={{ $json.folder_id }}",
              "type": "string"
            },
            {
              "id": "email-subject",
              "name": "email_subject",
              "value": "={{ $json.email_subject || 'No Subject' }}",
              "type": "string"
            },
            {
              "id": "email-body",
              "name": "body_core",
              "value": "={{ $json.body_core || '' }}",
              "type": "string"
            },
            {
              "id": "sender-name",
              "name": "contact_name",
              "value": "={{ $json.contact_name || '' }}",
              "type": "string"
            },
            {
              "id": "sender-email",
              "name": "contact_email",
              "value": "={{ $json.contact_email || '' }}",
              "type": "string"
            },
            {
              "id": "email-date",
              "name": "email_date",
              "value": "={{ $now.toISO() }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        4752,
        2880
      ],
      "id": "b0b3beae-8db4-4f45-b84e-ba0ceafd40e7",
      "name": "Prepare Input"
    },
    {
      "parameters": {
        "jsCode": "// Build email file with YAML frontmatter and ISO datetime filename\nconst input = $input.first().json;\n\n// ISO datetime for filename (replace colons with dashes for filesystem)\nconst isoDate = input.email_date.replace(/:/g, '-').split('.')[0];\nconst subjectSlug = input.email_subject\n  .toLowerCase()\n  .replace(/[^a-z0-9]+/g, '-')\n  .replace(/^-|-$/g, '')\n  .substring(0, 50);\nconst filename = `${isoDate}_${subjectSlug}.md`;\n\n// Build file content with YAML frontmatter\nconst directionLabel = input.direction === 'outbound' ? 'to' : 'from';\nconst fileContent = `---\nname: Email-${input.email_subject}\ndate: ${input.email_date}\ndirection: ${input.direction}\n${directionLabel}: ${input.contact_email}\n---\n\n${input.body_core}\n`;\n\n// Create binary data for upload\nconst binaryData = Buffer.from(fileContent, 'utf8').toString('base64');\n\nreturn [{\n  json: {\n    ...input,\n    filename: filename\n  },\n  binary: {\n    data: {\n      data: binaryData,\n      mimeType: 'text/markdown',\n      fileName: filename\n    }\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        4976,
        2880
      ],
      "id": "0257dc8b-ac3e-4896-b2de-829fea8385ff",
      "name": "Prepare Email File"
    },
    {
      "parameters": {
        "name": "={{ $json.filename }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "folderId": {
          "__rl": true,
          "value": "={{ $json.emails_folder_id }}",
          "mode": "id"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        5200,
        2880
      ],
      "id": "02b04ee4-14d3-4b8d-9e67-f4ca5395989a",
      "name": "Upload Email File",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "fileFolder",
        "searchMethod": "query",
        "limit": 1,
        "filter": {
          "folderId": {
            "__rl": true,
            "value": "={{ $('Prepare Input').first().json.folder_id }}",
            "mode": "id"
          },
          "whatToSearch": "files"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        5424,
        2880
      ],
      "id": "8749aa8a-4c4c-4935-94af-67ac2a1712e6",
      "name": "Find README",
      "alwaysOutputData": true,
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": {
          "__rl": true,
          "value": "={{ $json.id }}",
          "mode": "id"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        5648,
        2880
      ],
      "id": "50a58c20-dcb4-4182-bd45-171648a99d1a",
      "name": "Download README",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Extract README content from binary\nconst item = $input.first();\nconst binaryData = item.binary?.data;\nlet currentContent = '';\n\nif (binaryData) {\n  currentContent = Buffer.from(binaryData.data, 'base64').toString('utf8');\n}\n\nconst inputData = $('Prepare Input').first().json;\n\nreturn [{\n  json: {\n    readme_id: $('Find README').first().json.id,\n    readme_content: currentContent,\n    email_subject: inputData.email_subject,\n    body_core: inputData.body_core,\n    email_date: inputData.email_date,\n    contact_name: inputData.contact_name,\n    contact_email: inputData.contact_email,\n    direction: inputData.direction,\n    owner_name: inputData.owner_name\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        4752,
        3072
      ],
      "id": "14f43567-49a1-45b7-aafc-b373c786bbcb",
      "name": "Prep LLM Input"
    },
    {
      "parameters": {
        "model": "openai/gpt-oss-120b",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGroq",
      "typeVersion": 1,
      "position": [
        4976,
        3280
      ],
      "id": "1c4f8460-ddde-4efd-9043-a0953805e480",
      "name": "Profile LLM",
      "credentials": {
        "groqApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=You are managing the contact profiles for {{ $json.owner_name }}. Your task is to maintain a concise biographical profile of each contact.\n\n{{ $json.direction === 'outbound' ? 'CONTEXT: ' + $json.owner_name + ' SENT this email TO' : 'CONTEXT: ' + $json.owner_name + ' RECEIVED this email FROM' }} {{ $json.contact_name }} <{{ $json.contact_email }}>.\n\nRULES:\n1. Output ONLY plain text - NO YAML frontmatter (the system adds it automatically)\n2. Write 2-4 sentences about WHO THIS CONTACT IS (their company, role, what they do)\n3. If contact is a company/service (e.g. Railway, Stripe, AWS), describe what that company does\n4. DO NOT describe {{ $json.owner_name }} or their actions - only describe the contact\n5. DO NOT include operational details (support instructions, account changes, action items)\n6. Focus on durable facts: what company/person is this, what do they do, why might {{ $json.owner_name }} interact with them\n7. Merge new information with existing profile, update outdated info\n\n---\n\n## Current Profile:\n{{ $json.readme_content }}\n\n## {{ $json.direction === 'outbound' ? $json.owner_name + ' sent email TO' : 'Email FROM' }} {{ $json.contact_name }} <{{ $json.contact_email }}> ({{ $json.email_date }}):\nSubject: {{ $json.email_subject }}\n\n{{ $json.body_core }}\n\n---\nOutput ONLY a biographical profile of the contact (2-4 sentences, no YAML):",
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.7,
      "position": [
        4976,
        3072
      ],
      "id": "ee9a06ed-a862-4ee0-bc30-dd57e92f8088",
      "name": "LLM: Update Profile"
    },
    {
      "parameters": {
        "jsCode": "// Prepare updated README for upload\nconst llmOutput = $input.first().json.text || $input.first().json.output || '';\nconst readmeId = $('Prep LLM Input').first().json.readme_id;\n\n// Strip any YAML the LLM might have generated and get plain text only\nlet bioContent = llmOutput.trim();\n\n// Remove YAML frontmatter if LLM included it (it shouldn't, but safety check)\nif (bioContent.startsWith('---')) {\n  const endMarker = bioContent.indexOf('---', 3);\n  if (endMarker !== -1) {\n    bioContent = bioContent.substring(endMarker + 3).trim();\n  }\n}\n\n// Always use the fixed header\nconst fixedHeader = `---\\nname: ContactManager-Record\\ndescription: Most salient summary of the person that contacted me.\\n---\\n\\n`;\n\nconst content = `${fixedHeader}\\\n\\\n${bioContent}\\\n`;\n\nconst binaryData = Buffer.from(content, 'utf8').toString('base64');\n\nreturn [{\n  json: {\n    readme_id: readmeId,\n    content_preview: content\n  },\n  binary: {\n    data: {\n      data: binaryData,\n      mimeType: 'text/markdown',\n      fileName: 'README.md'\n    }\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        5200,
        3072
      ],
      "id": "9dcf7110-cd06-4ae1-9568-703b251d99f9",
      "name": "Prep README Upload"
    },
    {
      "parameters": {
        "operation": "update",
        "fileId": {
          "__rl": true,
          "value": "={{ $json.readme_id }}",
          "mode": "id"
        },
        "changeFileContent": true,
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        5424,
        3072
      ],
      "id": "042ad776-130a-4fb6-a268-fcf56e8a8bf1",
      "name": "Upload Updated README",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "status",
              "name": "status",
              "value": "success",
              "type": "string"
            },
            {
              "id": "email-file-id",
              "name": "email_file_id",
              "value": "={{ $('Upload Email File').first().json.id }}",
              "type": "string"
            },
            {
              "id": "email-file-name",
              "name": "email_file_name",
              "value": "={{ $('Prepare Email File').first().json.filename }}",
              "type": "string"
            },
            {
              "id": "readme-updated",
              "name": "readme_updated",
              "value": true,
              "type": "boolean"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        5648,
        3072
      ],
      "id": "4f81ee7b-fc3c-42bd-9416-12d1aaa5272f",
      "name": "Return Output"
    }
  ],
  "connections": {
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "Prepare Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Prepare Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Input": {
      "main": [
        [
          {
            "node": "Prepare Email File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Email File": {
      "main": [
        [
          {
            "node": "Upload Email File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Email File": {
      "main": [
        [
          {
            "node": "Find README",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find README": {
      "main": [
        [
          {
            "node": "Download README",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download README": {
      "main": [
        [
          {
            "node": "Prep LLM Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prep LLM Input": {
      "main": [
        [
          {
            "node": "LLM: Update Profile",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Profile LLM": {
      "ai_languageModel": [
        [
          {
            "node": "LLM: Update Profile",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "LLM: Update Profile": {
      "main": [
        [
          {
            "node": "Prep README Upload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prep README Upload": {
      "main": [
        [
          {
            "node": "Upload Updated README",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Updated README": {
      "main": [
        [
          {
            "node": "Return Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}