AutomationFlowsAI & RAG › Automated LinkedIn Job Hunt & Cover Letters

Automated LinkedIn Job Hunt & Cover Letters

Original n8n title: Linkedin Job Hunt and Cover Letter

LinkedIn_Job_Hunt_and_Cover_Letter. Uses outputParserStructured, outputParserAutofixing, googleDrive, agent. Scheduled trigger; 85 nodes.

Cron / scheduled trigger★★★★★ complexityAI-powered85 nodesOutput Parser StructuredOutput Parser AutofixingGoogle DriveAgentGmailGoogle Gemini ChatSupabaseNotion
AI & RAG Trigger: Cron / scheduled Nodes: 85 Complexity: ★★★★★ AI nodes: yes Added:
Automated LinkedIn Job Hunt & Cover Letters — n8n workflow card showing Output Parser Structured, Output Parser Autofixing, Google Drive integration

This workflow follows the Agent → Gmail 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
{
  "name": "LinkedIn_Job_Hunt_and_Cover_Letter",
  "nodes": [
    {
      "parameters": {
        "content": "## \u81ea\u52a8\u5316\u6c42\u804c\u52a9\u624b\uff08LinkedIn + Indeed\uff09\uff1a\u901a\u8fc7\u90ae\u4ef6\u83b7\u53d6\u6700\u4f73\u804c\u4f4d\u5339\u914d + \u751f\u6210\u6c42\u804c\u4fe1 + \u4fdd\u5b58\u5230Notion\n\n**\u4f5c\u8005**: Wen\n**Email\u5730\u5740**: wenjiaqi8255@outlook.com\n\n**\u63cf\u8ff0**: \n\u6b64n8n\u5de5\u4f5c\u6d41\u7a0b\u65e8\u5728\u81ea\u52a8\u5316\u5bfb\u627e\u548c\u63a8\u9001\u6700\u4f73\u804c\u4f4d\u63a8\u8350\u7684\u8fc7\u7a0b\u3002\u5b83\u4f1a\u83b7\u53d6\u60a8\u7684\u7b80\u5386\uff0c\u4eceLinkedIn\u548cIndeed\u6293\u53d6\u804c\u4f4d\u5217\u8868\uff0c\u4f7f\u7528AI\uff08Google Gemini\uff09\u5c06\u804c\u4f4d\u4e0e\u60a8\u7684\u7b80\u5386\u8fdb\u884c\u5339\u914d\uff0c\u7136\u540e\u901a\u8fc7\u7535\u5b50\u90ae\u4ef6\u53d1\u9001\u6700\u4f73\u804c\u4f4d\u63a8\u8350\u7ed9\u60a8\u3002\u8be5\u5de5\u4f5c\u6d41\u7a0b\u6309\u8ba1\u5212\u81ea\u52a8\u8fd0\u884c\u3002\n\n**\u6838\u5fc3\u529f\u80fd**:\n- \u7b80\u5386\u4e0e\u804c\u4f4d\u81ea\u52a8\u5339\u914d\n- \u4e2a\u6027\u5316\u6c42\u804c\u4fe1\u751f\u6210\n- \u5b9a\u65f6\u90ae\u4ef6\u63a8\u9001\u9ad8\u5339\u914d\u5ea6\u804c\u4f4d\n- Notion\u4e00\u4f53\u5316\u804c\u4f4d\u7ba1\u7406\n- \u591a\u5e73\u53f0\u804c\u4f4d\u6570\u636e\u6c47\u603b\uff08LinkedIn, Indeed\uff09\n\n**Credit**: Tianyi tianyi.datascience@gmail.com",
        "height": 820,
        "width": 640,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -2460,
        -600
      ],
      "id": "bcd6de88-108f-4743-875d-af3fd117ca4e",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 8
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        -2380,
        580
      ],
      "id": "1eba2d78-167b-43d8-9260-5ebe1fa59016",
      "name": "Schedule Trigger"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "a08ebfd2-be88-4870-9f83-9430eda33d56",
              "name": "Resume",
              "value": "={{ $json.text }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -1040,
        580
      ],
      "id": "5dbb0ffa-7d5c-49ef-843e-32626bbd5f86",
      "name": "SetResumeField"
    },
    {
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n    \"database_id\": 1,\n    \"Company Name\": \"Innovatech Solutions\",\n    \"Job Title\": \"Senior Software Engineer\",\n    \"Industry\": \"Technology / SaaS\",\n    \"Reason for Match\": \"Strong alignment with your 7 years of backend development experience (Java/Spring) listed in CV and your preference for mid-sized tech companies.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/1234567890\",\n    \"Location\": \"San Francisco, CA\",\n    \"Flexibility\": \"Hybrid\",\n    \"Salary Range\": \"$120,000 - $150,000\"\n}"
      },
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "typeVersion": 1.2,
      "position": [
        2960,
        680
      ],
      "id": "d2f5bddf-9623-44b1-85d3-9873935b3768",
      "name": "Structured Output Parser"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.outputParserAutofixing",
      "typeVersion": 1,
      "position": [
        2740,
        460
      ],
      "id": "d5aefbc3-cbc1-4e80-b1e7-2adaa2b51c17",
      "name": "Auto-fixing Output Parser"
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": {
          "__rl": true,
          "value": "1Sk87acRe343xHRCzjffoLmuq1oAaI1Zt",
          "mode": "list",
          "cachedResultName": "your_cv.pdf",
          "cachedResultUrl": "https://drive.google.com/file/d/your_cv.pdf/view?usp=sharing"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        -1500,
        580
      ],
      "id": "0b7b87e5-101d-472f-a709-19e3a33d43db",
      "name": "DownloadResume",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "pdf",
        "options": {}
      },
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1,
      "position": [
        -1280,
        580
      ],
      "id": "09873953-c590-48c9-8604-da1ab5736ae4",
      "name": "Extract Information from Resume PDF"
    },
    {
      "parameters": {
        "promptType": "=define",
        "text": "=You are an expert AI assistant specializing in career matching and job recommendation.\n\nYour Goal:\nYour primary task is to analyze a provided dataset of 100 LinkedIn job descriptions , a user's Curriculum Vitae (CV) provided as a string, and the user's job preferences is also provided as a string. Based on this analysis, you must identify and select the top 5 most suitable job opportunities for the user from the provided list.\n\nInputs You Will Receive:\n\njob_descriptions {{ $('stringify_json').item.json.stringified }}: A collection containing 100 job descriptions scraped from LinkedIn. Each job has the following structure:\n{\n  \"id\": [database ID],\n  \"company_name\": [company name],\n  \"job_title\": [job title],\n  \"industry\": [industry],\n  \"application_url\": [URL],\n  \"location\": [job location],\n  \"flexibility\": [work arrangement],\n  \"salary_range\": [salary if available],\n  \"created_at\": [timestamp]\n}\nuser_cv {{ $('SetResumeField').first().json.Resume }}: A single string containing the user's full CV text.\nuser_preferences {{ $('Input').first().json.Preference }}: A single string outlining the user's job preferences (e.g., desired roles, industries, company size, location constraints, salary expectations, work culture).\n\nYour Task Breakdown:\n\nAnalyze: Meticulously parse and understand the content of the user_cv and user_preferences.\nEvaluate: For each of the 100 job_descriptions:\nExtract key information: Company Name, Job Title, Industry (if explicitly mentioned or inferable), and Application URL.\nCompare the job's requirements, responsibilities, and company details against the user's skills, experience (from user_cv), and stated desires (from user_preferences).\nRank: Assess the suitability of each job for the user based on the comparison. Create a ranked list of all 100 jobs from most to least suitable.\nSelect: Choose the top {{ $('Input').first().json.RecommendedJobCount || 8 }} from your ranked list.\nFormat Output: Prepare the final output containing detailed information for only these 8 selected jobs.\n\nOutput Requirements:\n\nYou must return a structured list containing exactly 8 job recommendations. For each of the 8 jobs, provide the following specific details:\n\ndatabase_id: The \"id\" field from the job record.\nCompany Name: The name of the hiring company from \"company_name\".\nJob Title: The official title of the position from \"job_title\".\nIndustry: The industry sector from \"industry\" (if available).\nReason for Match: A brief (1-2 sentences) explanation justifying why this specific job is a strong match for the user. This explanation should explicitly reference alignment between the user's CV/preferences and the job description.\nApplication URL: The direct URL to apply from \"application_url\". If the apply URL is not found or empty, return the linkedin link for this job.\nLocation: The job location from \"location\".\nFlexibility: Work arrangement type from \"flexibility\".\nSalary Range: Salary information from \"salary_range\" if available, otherwise \"Not specified\".\n\nOutput format Example:\n[\n  {\n    \"database_id\": 1,\n    \"Company Name\": \"Innovatech Solutions\",\n    \"Job Title\": \"Senior Software Engineer\",\n    \"Industry\": \"Technology / SaaS\",\n    \"Reason for Match\": \"Strong alignment with your 7 years of backend development experience (Java/Spring) listed in CV and your preference for mid-sized tech companies.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/1234567890\",\n    \"Location\": \"San Francisco, CA\",\n    \"Flexibility\": \"Hybrid\",\n    \"Salary Range\": \"$120,000 - $150,000\"\n  },\n  {\n    \"database_id\": 2,\n    \"Company Name\": \"FinSecure Corp\",\n    \"Job Title\": \"Data Scientist\",\n    \"Industry\": \"Financial Services\",\n    \"Reason for Match\": \"Matches your PhD in Statistics, experience with machine learning models detailed in your CV, and stated interest in the Fintech sector.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/0987654321\",\n    \"Location\": \"New York, NY\",\n    \"Flexibility\": \"On-site\",\n    \"Salary Range\": \"$110,000 - $130,000\"\n  },\n  {\n    \"database_id\": 3,\n    \"Company Name\": \"Global Health Initiative\",\n    \"Job Title\": \"Biostatistician\",\n    \"Industry\": \"Healthcare / Research\",\n    \"Reason for Match\": \"Aligns with your strong statistical background and published research in healthcare outcomes mentioned in your CV.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/5678901234\",\n    \"Location\": \"Boston, MA\",\n    \"Flexibility\": \"Hybrid\",\n    \"Salary Range\": \"Not specified\"\n  },\n  {\n    \"database_id\": 4,\n    \"Company Name\": \"EcoSolutions\",\n    \"Job Title\": \"Sustainability Analyst\",\n    \"Industry\": \"Environmental Services\",\n    \"Reason for Match\": \"Matches your environmental science background and stated preference for working in sustainability-focused organizations.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/2345678901\",\n    \"Location\": \"Portland, OR\",\n    \"Flexibility\": \"Remote\",\n    \"Salary Range\": \"$85,000 - $95,000\"\n  },\n  {\n    \"database_id\": 5,\n    \"Company Name\": \"TechStart Accelerator\",\n    \"Job Title\": \"Technology Consultant\",\n    \"Industry\": \"Consulting\",\n    \"Reason for Match\": \"Aligns with your technical advisory experience and preference for varied project work mentioned in your preferences.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/3456789012\",\n    \"Location\": \"Austin, TX\",\n    \"Flexibility\": \"Hybrid\",\n    \"Salary Range\": \"$100,000 - $120,000\"\n  },\n  {\n    \"database_id\": 6,\n    \"Company Name\": \"TechStart Accelerator\",\n    \"Job Title\": \"Technology Consultant\",\n    \"Industry\": \"Consulting\",\n    \"Reason for Match\": \"Aligns with your technical advisory experience and preference for varied project work mentioned in your preferences.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/3456789012\",\n    \"Location\": \"Austin, TX\",\n    \"Flexibility\": \"Hybrid\",\n    \"Salary Range\": \"$100,000 - $120,000\"\n  },\n  {\n    \"database_id\": 7,\n    \"Company Name\": \"TechStart Accelerator\",\n    \"Job Title\": \"Technology Consultant\",\n    \"Industry\": \"Consulting\",\n    \"Reason for Match\": \"Aligns with your technical advisory experience and preference for varied project work mentioned in your preferences.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/3456789012\",\n    \"Location\": \"Austin, TX\",\n    \"Flexibility\": \"Hybrid\",\n    \"Salary Range\": \"$100,000 - $120,000\"\n  },\n  {\n    \"database_id\": 8,\n    \"Company Name\": \"TechStart Accelerator\",\n    \"Job Title\": \"Technology Consultant\",\n    \"Industry\": \"Consulting\",\n    \"Reason for Match\": \"Aligns with your technical advisory experience and preference for varied project work mentioned in your preferences.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/3456789012\",\n    \"Location\": \"Austin, TX\",\n    \"Flexibility\": \"Hybrid\",\n    \"Salary Range\": \"$100,000 - $120,000\"\n  }\n]",
        "hasOutputParser": true,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.8,
      "position": [
        2620,
        220
      ],
      "id": "c76cea73-18b0-42fa-a3ab-550a4e2bfc5d",
      "name": "AI Agent: Find Best-matched jobs",
      "retryOnFail": true,
      "executeOnce": true
    },
    {
      "parameters": {
        "sendTo": "={{ $('Input').first().json.EmailAddressToReceiveJobRecommendations}}",
        "subject": "=Best-Matched Jobs - {{ $now.format('yyyy-MM-dd') }} ",
        "message": "={{$input.item.json.html}}",
        "options": {}
      },
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        4040,
        560
      ],
      "id": "040a2699-d850-4238-8b3b-00a7f2e5ce75",
      "name": "Email the top job recommendations",
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "content": "### Schedule Trigger\n\u6b64\u8282\u70b9\u89e6\u53d1\u5de5\u4f5c\u6d41\u7a0b\u6309\u6307\u5b9a\u65f6\u95f4\u81ea\u52a8\u8fd0\u884c\u3002\u9ed8\u8ba4\u8bbe\u7f6e\u4e3a\u6bcf\u5929\u65e9\u4e0a8:00\u89e6\u53d1\uff0c\u60a8\u53ef\u4ee5\u6839\u636e\u9700\u6c42\u8c03\u6574\u65f6\u95f4\u9891\u7387\u3002\n\u6ce8\uff1a\u5728n8n Settings\u91cc\u53ef\u8bbe\u7f6e\u65f6\u533a",
        "height": 640,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -2460,
        280
      ],
      "id": "4258d07a-938b-4a6b-ac7f-2bbc0d070d6c",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "### Input\n**\u5173\u952e\u914d\u7f6e\u8282\u70b9**\n\u8fd9\u91cc\u8bbe\u7f6e\u4e86\u6574\u4e2a\u5de5\u4f5c\u6d41\u7a0b\u4e2d\u4f7f\u7528\u7684\u91cd\u8981\u53d8\u91cf\uff1a\n- **ApifyAPIKey**: \u7528\u4e8e\u8bbf\u95eeApify\u670d\u52a1\u7684API\u5bc6\u94a5\n- **Preference**: \u60a8\u7684\u6c42\u804c\u504f\u597d\uff0c\u5f71\u54cdAI\u5339\u914d\u7ed3\u679c\n- **EmailAddressToReceiveJobRecommendations**: \u63a5\u6536\u804c\u4f4d\u63a8\u8350\u7684\u90ae\u7bb1\n- **recommendedJobCount**: \u6bcf\u6b21\u63a8\u8350\u7684\u804c\u4f4d\u6570\u91cf\n- **first_timeout**: \u9996\u6b21API\u8bf7\u6c42\u8d85\u65f6\u65f6\u95f4\uff08\u79d2\uff09\n- **request_interval**: \u91cd\u8bd5\u8bf7\u6c42\u95f4\u9694\u65f6\u95f4\uff08\u79d2\uff09",
        "height": 640,
        "width": 500,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -2160,
        280
      ],
      "id": "b1622b06-9a1b-4e68-8947-4df119793d9b",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "content": "### DownloadResume\n\u4eceGoogle Drive\u4e0b\u8f7d\u60a8\u7684\u7b80\u5386PDF\u6587\u4ef6\u3002\u8bf7\u786e\u4fdd\u4e0a\u4f20\u60a8\u7684\u7b80\u5386\u5230Google Drive\u5e76\u83b7\u53d6\u6587\u4ef6ID\u3002\n\n### Extract Information from Resume PDF\n\u63d0\u53d6\u7b80\u5386PDF\u4e2d\u7684\u6587\u672c\u5185\u5bb9\uff0c\u4e3a\u540e\u7eedAI\u5339\u914d\u505a\u51c6\u5907\u3002\n\n### SetResumeField\n\u5c06\u63d0\u53d6\u7684\u7b80\u5386\u6587\u672c\u8bbe\u7f6e\u4e3a\u53d8\u91cf\uff0c\u4ee5\u4fbf\u5728\u5de5\u4f5c\u6d41\u7a0b\u7684\u540e\u7eed\u6b65\u9aa4\u4e2d\u4f7f\u7528\u3002",
        "height": 640,
        "width": 740
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1600,
        280
      ],
      "id": "08001c75-b495-4ad1-bc8b-f8cd8875dbf1",
      "name": "Sticky Note3"
    },
    {
      "parameters": {
        "content": "### start_apify_run_linkedin\n\u542f\u52a8Apify\u722c\u866b\uff0c\u6293\u53d6LinkedIn\u4e0a\u7684\u804c\u4f4d\u4fe1\u606f\u3002\n\u786e\u4fdd\u5728jsonBody\u4e2d\u8bbe\u7f6e\u6b63\u786e\u7684\u641c\u7d22URL\u548c\u53c2\u6570\u3002\n\n### Check Run Status / Get Dataset Items\n\u8fd9\u4e9b\u8282\u70b9\u68c0\u67e5\u722c\u866b\u8fd0\u884c\u72b6\u6001\u5e76\u83b7\u53d6\u7ed3\u679c\u6570\u636e\u3002\n\u5305\u542b\u9519\u8bef\u5904\u7406\u548c\u91cd\u8bd5\u673a\u5236\uff0c\u786e\u4fdd\u53ef\u9760\u83b7\u53d6\u804c\u4f4d\u4fe1\u606f\u3002\n",
        "height": 640,
        "width": 1280,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -800,
        280
      ],
      "id": "27bf44a1-cbb7-4c10-b991-ca1b67582d25",
      "name": "Sticky Note6"
    },
    {
      "parameters": {
        "content": "\n### Merge\n\u5408\u5e76\u6765\u81eaLinkedIn\u548cIndeed\u7684\u804c\u4f4d\u6570\u636e\uff0c\u521b\u5efa\u7edf\u4e00\u7684\u804c\u4f4d\u5217\u8868\u3002",
        "height": 640,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        840,
        280
      ],
      "id": "5c9525bd-3d5c-422e-b432-df6a5365f24b",
      "name": "Sticky Note7"
    },
    {
      "parameters": {
        "content": "### AI Agent: Find Best-matched jobs\n**\u6838\u5fc3\u5339\u914d\u8282\u70b9**\n\n**\u8f93\u5165**:\n- **scraped_job_data**: \u4eceLinkedIn\u548cIndeed\u6293\u53d6\u7684\u6240\u6709\u804c\u4f4d\u4fe1\u606f\n- **user_cv**: \u7528\u6237\u7b80\u5386\u6587\u672c\uff08\u4ecePDF\u63d0\u53d6\uff09\n- **user_preferences**: \u7528\u6237\u7684\u6c42\u804c\u504f\u597d\u8bbe\u7f6e\uff08\u5982\u5730\u70b9\u3001\u884c\u4e1a\u3001\u85aa\u8d44\u671f\u671b\u7b49\uff09\n- **recommendedJobCount**: \u9700\u8981\u5339\u914d\u7684\u804c\u4f4d\u6570\u91cf\n\n**\u8f93\u51fa**:\n\u7ed3\u6784\u5316\u5217\u8868\uff0c\u5305\u542b\u63a8\u8350\u804c\u4f4d\u7684\u8be6\u7ec6\u4fe1\u606f\uff1a\n- **database_id**: \u804c\u4f4d\u8bb0\u5f55ID\n- **Company Name**: \u62db\u8058\u516c\u53f8\u540d\u79f0\n- **Job Title**: \u804c\u4f4d\u540d\u79f0\n- **Industry**: \u884c\u4e1a\u9886\u57df\n- **Reason for Match**: \u5339\u914d\u539f\u56e0\u8bf4\u660e\uff081-2\u53e5\u8bdd\u8bf4\u660e\u4e3a\u4f55\u6b64\u804c\u4f4d\u4e0e\u7528\u6237\u5339\u914d\uff09\n- **Application URL**: \u7533\u8bf7\u94fe\u63a5\n- **Location**: \u5de5\u4f5c\u5730\u70b9\n- **Flexibility**: \u5de5\u4f5c\u5b89\u6392\u65b9\u5f0f\uff08\u8fdc\u7a0b\u3001\u6df7\u5408\u3001\u73b0\u573a\u7b49\uff09\n- **Salary Range**: \u85aa\u8d44\u8303\u56f4\uff08\u5982\u6709\uff09",
        "height": 1200,
        "width": 580,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        2500,
        -280
      ],
      "id": "8a4d335c-a196-4333-8fa9-9e8281f77a8a",
      "name": "Sticky Note9"
    },
    {
      "parameters": {
        "content": "### Email the top job recommendations\n\u5c06\u6700\u4f73\u5339\u914d\u7684\u804c\u4f4d\u901a\u8fc7\u7535\u5b50\u90ae\u4ef6\u53d1\u9001\u7ed9\u60a8\uff0c\u90ae\u4ef6\u5305\u542b\u804c\u4f4d\u6807\u9898\u3001\u516c\u53f8\u3001\u5730\u70b9\u3001\u85aa\u8d44\u548c\u7533\u8bf7\u94fe\u63a5\u7b49\u4fe1\u606f\u3002",
        "height": 620,
        "color": 2
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        3980,
        300
      ],
      "id": "04c1ad11-ce69-4cbc-b8dc-facda79487e2",
      "name": "Sticky Note10"
    },
    {
      "parameters": {
        "content": "## \u5de5\u4f5c\u6d41\u7a0b\u8bbe\u7f6e\u6307\u5357\n### \u8bf7\u6309\u7167\u4ee5\u4e0b\u6b65\u9aa4\u8bbe\u7f6e\u5de5\u4f5c\u6d41\u7a0b\uff1a\n\n### 1. \u914d\u7f6e\u8f93\u5165\u8282\u70b9\uff1a\n\u6253\u5f00\u5de5\u4f5c\u6d41\u4e2d\u7684\"Input\"\u8282\u70b9\u3002\n\u586b\u5199\u5fc5\u586b\u5b57\u6bb5\uff1a\n- **ApifyAPIKey**: \u8f93\u5165\u60a8\u7684Apify API\u5bc6\u94a5\uff08\u767b\u5f55Apify: https://www.apify.com?fpr=oljm1 -> \u8bbe\u7f6e -> API & Integration\uff09\n- **Preference**: \u6307\u5b9a\u60a8\u7684\u6c42\u804c\u504f\u597d\uff08\u5982\"\u65e0\u5fb7\u8bed\u8981\u6c42\uff0c\u9ad8\u85aa\"\uff09\n- **EmailAddressToReceiveJobRecommendations**: \u63d0\u4f9b\u60a8\u5e0c\u671b\u63a5\u6536\u804c\u4f4d\u63a8\u8350\u7684\u7535\u5b50\u90ae\u4ef6\u5730\u5740\n- **recommendedJobCount**: \u8bbe\u7f6e\u6bcf\u6b21\u63a8\u8350\u7684\u804c\u4f4d\u6570\u91cf\uff08\u9ed8\u8ba4\u4e3a10\uff09\n\n### 2. \u914d\u7f6eLinkedIn\u804c\u4f4d\u641c\u7d22URL\uff1a\n\n- \u5728\u6d4f\u89c8\u5668\u7684\u9690\u79c1/\u65e0\u75d5\u7a97\u53e3\u4e2d\u6253\u5f00LinkedIn Jobs\u641c\u7d22\u9875\u9762\uff1ahttps://www.linkedin.com/jobs/search/\n- \u4f7f\u7528LinkedIn\u641c\u7d22\u754c\u9762\u8bbe\u7f6e\u60a8\u9700\u8981\u7684\u7b5b\u9009\u6761\u4ef6\uff08\u5173\u952e\u8bcd\u3001\u5730\u70b9\u3001\u7ecf\u9a8c\u6c34\u5e73\u7b49\uff09\u3002**\u52a1\u5fc5\u6dfb\u52a0\"\u8fc7\u53bb24\u5c0f\u65f6\"\u7b5b\u9009\u6761\u4ef6**\n- \u590d\u5236\u6d4f\u89c8\u5668\u5730\u5740\u680f\u4e2d\u7684\u5b8c\u6574URL\n- \u6253\u5f00\u5de5\u4f5c\u6d41\u4e2d\u7684\"start_apify_run_linkedin\"\u8282\u70b9\n- \u5728\"jsonBody\"\u53c2\u6570\u4e2d\u627e\u5230\"urls\"\u6570\u7ec4\uff1a\n  ```json\n  \"urls\": [\n      \"https://www.linkedin.com/jobs/search/...\"\n  ]\n\n\u5c06\u73b0\u6709URL\uff08\"https://www.linkedin.com/jobs/search/...\"\uff09\u66ff\u6362\u4e3a\u60a8\u4ece\u9690\u79c1\u7a97\u53e3\u590d\u5236\u7684\u5b8c\u6574URL\u3002\u786e\u4fddURL\u7528\u53cc\u5f15\u53f7\u62ec\u8d77\u6765\n\n3. \u914d\u7f6eIndeed\u804c\u4f4d\u641c\u7d22\uff08\u53ef\u9009\uff09\uff1a\n\n\u7c7b\u4f3c\u5730\uff0c\u53ef\u4ee5\u5728\"start_apify_run_indeed\"\u8282\u70b9\u4e2d\u914d\u7f6eIndeed\u641c\u7d22\u53c2\u6570\n\u81ea\u5b9a\u4e49\u641c\u7d22\u5173\u952e\u8bcd\u3001\u5730\u70b9\u548c\u5176\u4ed6\u53c2\u6570\u4ee5\u7b26\u5408\u60a8\u7684\u6c42\u804c\u9700\u6c42\n\n4. \u4e0a\u4f20\u60a8\u7684\u7b80\u5386\uff1a\n\n\u5c06\u60a8\u7684\u7b80\u5386\uff08PDF\u683c\u5f0f\uff09\u4e0a\u4f20\u5230Google Drive\n\u5728\"DownloadResume\"\u8282\u70b9\u4e2d\u66f4\u65b0\u6587\u4ef6ID\u4ee5\u6307\u5411\u60a8\u7684\u7b80\u5386\n\n",
        "height": 820,
        "width": 900,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1760,
        -600
      ],
      "id": "831b9298-2b78-49db-83a0-4eaf7dcee63d",
      "name": "Sticky Note11"
    },
    {
      "parameters": {
        "modelName": "models/gemini-2.0-flash",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1,
      "position": [
        2600,
        420
      ],
      "id": "d83824f0-9c3d-4bd6-a448-eb8fa552b074",
      "name": "Google Gemini Chat Model",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "modelName": "models/gemini-2.0-flash",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1,
      "position": [
        2700,
        660
      ],
      "id": "e6a594bb-5cb2-497c-a799-b37ac8c9a243",
      "name": "Google Gemini Chat Model1",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "tableId": "job_listings",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "company_name",
              "fieldValue": "={{ $json.company_name }}"
            },
            {
              "fieldId": "job_title",
              "fieldValue": "={{ $json.job_title }}"
            },
            {
              "fieldId": "industry",
              "fieldValue": "={{ $json.industry }}"
            },
            {
              "fieldId": "application_url",
              "fieldValue": "={{ $json.application_url }}"
            },
            {
              "fieldId": "location",
              "fieldValue": "={{ $json.location }}"
            },
            {
              "fieldId": "flexibility",
              "fieldValue": "={{ $json.flexibility }}"
            },
            {
              "fieldId": "salary_range",
              "fieldValue": "={{ $json.salary_range }}"
            },
            {
              "fieldId": "id",
              "fieldValue": "={{ $json.id }}"
            },
            {
              "fieldId": "description",
              "fieldValue": "={{ $json.description.substring(0,4000) }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        1860,
        440
      ],
      "id": "698fcc9b-0a64-4f8c-b0f4-9f2c2b0f48f3",
      "name": "Supabase",
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "path": "2f32a889-c6d8-4dda-a550-71d963063aa7",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        -2900,
        2220
      ],
      "id": "d9951f93-3343-4622-be8f-27aa22489dd7",
      "name": "Webhook"
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": {
          "__rl": true,
          "value": "1BFLqG74itZyelxhdJrAjgHTGAJNiECeR",
          "mode": "list",
          "cachedResultName": "your_cv.pdf",
          "cachedResultUrl": "https://drive.google.com/file/d/your_cv.pdf/view?usp=sharing"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        -1500,
        2220
      ],
      "id": "288968e3-8d8f-49ba-95d1-c8ced682d0b5",
      "name": "DownloadResume1",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "get",
        "tableId": "job_listings",
        "filters": {
          "conditions": [
            {
              "keyName": "id",
              "keyValue": "={{ $('get_job_id').item.json.jobId }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        -2160,
        2220
      ],
      "id": "09770e2e-d7d5-4556-91f9-0eeb5d52e7d1",
      "name": "Supabase_get",
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// \u4eceWebhook\u8c03\u7528\u4e2d\u63d0\u53d6jobId\u53c2\u6570\nconst jobId = $('Webhook').first().json?.query?.jobId;\n\nif (!jobId) {\n  return {\n    json: {\n      success: false,\n      message: \"Missing job ID parameter. Please provide a jobId query parameter.\"\n    }\n  };\n}\n\nreturn {\n  json: {\n    success: true,\n    jobId: jobId\n  }\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -2320,
        2220
      ],
      "id": "7a0b34f3-df6b-4dd9-a13a-810171ef9536",
      "name": "get_job_id"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=# Cover Letter Assistant\n\nYou are a professional cover letter consultant who creates authentic, targeted, and personalized cover letters. Your task is to create an effective cover letter based on a job description and resume.\n\n## Basic Information\n\nPosition: {{ $('Supabase_get').item.json.job_title }}\nCompany: {{ $('Supabase_get').item.json.company_name }}\nIndustry: {{ $('Supabase_get').item.json.industry }}\nLocation: {{ $('Supabase_get').item.json.location }}\n\nJob Description: {{ $('Supabase_get').item.json.description }}\nResume Content: {{ $json.text }}\n\n## Cover Letter Guidelines\n\n### Core Principles\n\n1. **Company-needs focused**: Start with \"how my skills solve this company's specific problems\" rather than simply listing personal achievements\n2. **Concise and direct**: Use clear, short sentences; avoid complex structures and decorative vocabulary\n3. **Authentic personality**: Show the applicant's genuine work style and personality, avoid clich\u00e9s\n4. **Targeted approach**: Address key requirements from the job description directly, not vaguely\n5. **Quality over quantity**: Prefer a few powerful examples rather than many vague accomplishments\n\n### Structure Suggestions\n\n**Opening paragraph**:\n- Briefly express why you're interested in this position\n- Mention a specific company project, value, or challenge, showing your research\n- Keep within 2-3 short sentences\n\n**Skills matching paragraphs**:\n- Focus each paragraph on one core skill or company need\n- State the company's need first, then introduce your relevant experience\n- Provide 1-2 specific examples, using data only when actually supported\n- Keep each paragraph to 3-4 short sentences\n\n**Unique value paragraph**:\n- Include a paragraph showcasing your unique advantage\n- This could be a relevant side project, special skill, or personal work approach\n- Show how this unique value benefits the company\n\n**Closing paragraph**:\n- Simply express your interest in further discussion\n- Consider mentioning your personal website or portfolio\n- Keep it brief, 2-3 sentences is enough\n\n### Language Style Guide\n\n- Use active language, avoid passive voice\n- Avoid clich\u00e9s like \"I am excited to apply...\" or \"I believe I am the best candidate...\"\n- Adjust tone for company culture: technical companies use precise terminology, creative companies emphasize innovative thinking, etc.\n- Use natural, conversational language, as if talking with the hiring manager\n\n### Common Mistakes to Avoid\n\n- Overusing industry jargon and abbreviations\n- Long paragraphs and complex sentences\n- Data claims without supporting context\n- Vague achievement descriptions\n- Too much focus on \"what I did\" rather than \"what I can do for you\"\n\n## Final Check\n\nBefore finalizing, ensure the cover letter:\n- Totals 300-400 words (not exceeding one page)\n- Uses no templated expressions or business clich\u00e9s\n- Addresses all key requirements from the job description\n- Has a clear focus and natural transitions in each paragraph\n- Shows the applicant's personality and work style\n- Is oriented toward solving company problems\n\nPlease create a cover letter following these guidelines, keeping it authentic, concise, and targeted.",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.9,
      "position": [
        -1040,
        2220
      ],
      "id": "ff220f55-7235-4360-b23b-aaf6b766a433",
      "name": "AI Agent"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "9ba8a38a-17fc-4b4a-8a4e-6981b92cbee4",
              "name": "ApifyAPIKey",
              "value": "apify_api_your_api_key",
              "type": "string"
            },
            {
              "id": "a08ebfd2-be88-4870-9f83-9430eda33d56",
              "name": "Preference",
              "value": "=no German proficiency requirement, high pay",
              "type": "string"
            },
            {
              "id": "82b79f4d-43b9-4a36-80df-0d4ca51ab5e5",
              "name": "EmailAddressToReceiveJobRecommendations",
              "value": "your@email.com",
              "type": "string"
            },
            {
              "id": "3ee98ee6-7c9f-4f2c-afe7-12bb4d53c7c2",
              "name": "recommendedJobCount",
              "value": 10,
              "type": "number"
            },
            {
              "id": "b4c797c5-da56-47e1-84c1-ce64ea9b508e",
              "name": "first_timeout",
              "value": 60,
              "type": "number"
            },
            {
              "id": "8e16b176-2cd3-448a-a859-6570cacda1f0",
              "name": "request_interval",
              "value": 30,
              "type": "number"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -1980,
        580
      ],
      "id": "f9734f5e-1ea9-4407-84b4-3ab299e87b3a",
      "name": "Input"
    },
    {
      "parameters": {
        "sendTo": "={{ $('Input1').first().json.EmailAddressToReceiveCoverLetter}}",
        "subject": "Cover Letter",
        "message": "={{ $json.data }}",
        "options": {}
      },
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        -60,
        2220
      ],
      "id": "ad6411f2-2608-4f7f-9efe-3b6656710d0d",
      "name": "Gmail",
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "markdownToHtml",
        "markdown": "={{ $('AI Agent').item.json.output }}",
        "options": {}
      },
      "type": "n8n-nodes-base.markdown",
      "typeVersion": 1,
      "position": [
        -260,
        2220
      ],
      "id": "30683ac7-89bd-4df4-9071-593ee43d4e1f",
      "name": "Markdown"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "97e6b24a-a185-4e8e-9767-b0fe88264885",
              "name": "stringified",
              "value": "={{ JSON.stringify($json) }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        2320,
        580
      ],
      "id": "a3930751-dacb-4c9d-89be-b2fc42590513",
      "name": "stringify_json"
    },
    {
      "parameters": {
        "operation": "pdf",
        "options": {}
      },
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1,
      "position": [
        -1320,
        2220
      ],
      "id": "899a0ede-0749-4e88-9539-8fb4d9a5fa95",
      "name": "Extract Information from Resume PDF1"
    },
    {
      "parameters": {
        "operation": "getAll",
        "tableId": "job_listings",
        "returnAll": true
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        1220,
        580
      ],
      "id": "0b09f2ef-e1f2-4535-9e35-be43e37651e2",
      "name": "Supabase1",
      "executeOnce": true,
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// \u83b7\u53d6AI Agent\u7684\u8f93\u51fa\u6587\u672c\nconst fullText = $('set_cover_letter').first().json.output;\n\n// \u6309\u81ea\u7136\u6bb5\u843d\u5206\u5272\u6587\u672c\nconst paragraphs = fullText.split(\"\\n\\n\");\n\n// \u63d0\u53d6\u7b2c\u4e00\u6bb5\u4f5c\u4e3a\u6807\u9898\uff08\u53ef\u9009\uff09\nconst title = paragraphs[0].trim();\n\n// \u521b\u5efa\u5757\u5185\u5bb9\nconst blocks = [];\n\nparagraphs.forEach((paragraph, index) => {\n  if (paragraph.trim().length > 0) {\n    // \u786e\u4fdd\u6bb5\u843d\u4e0d\u8d85\u8fc72000\u5b57\u7b26\n    if (paragraph.length > 2000) {\n      // \u5982\u679c\u8d85\u8fc7\uff0c\u8fdb\u4e00\u6b65\u5206\u5272\n      let startIdx = 0;\n      while (startIdx < paragraph.length) {\n        const chunk = paragraph.substring(startIdx, Math.min(startIdx + 1900, paragraph.length));\n        blocks.push({\n          \"type\": \"paragraph\",\n          \"paragraph\": {\n            \"rich_text\": [{\n              \"type\": \"text\",\n              \"text\": {\n                \"content\": chunk\n              }\n            }]\n          }\n        });\n        startIdx += 1900;\n      }\n    } else {\n      // \u5982\u679c\u6bb5\u843d\u957f\u5ea6\u5408\u9002\uff0c\u76f4\u63a5\u6dfb\u52a0\n      blocks.push({\n        \"type\": \"paragraph\",\n        \"paragraph\": {\n          \"rich_text\": [{\n            \"type\": \"text\",\n            \"text\": {\n              \"content\": paragraph\n            }\n          }]\n        }\n      });\n    }\n  }\n});\n\n// \u8fd4\u56de\u7ed3\u679c\uff0c\u5305\u542b\u6807\u9898\u548c\u5757\nreturn {\n  json: {\n    title: title,\n    blocks: blocks\n  }\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -440,
        2220
      ],
      "id": "0d98d61f-bd18-4022-beba-49d7e4b9ebd3",
      "name": "parse_to_markdown"
    },
    {
      "parameters": {
        "jsCode": "// \u83b7\u53d6AI Agent\u7684\u8f93\u51fa\u6587\u672c\nconst fullText = $('set_cover_letter').first().json.output;\n\n// \u6309\u81ea\u7136\u6bb5\u843d\u5206\u5272\u6587\u672c\nconst paragraphs = fullText.split(\"\\n\\n\");\n\n// \u521b\u5efa\u591a\u4e2a\u8f93\u51fa\u9879\uff0c\u6bcf\u9879\u5bf9\u5e94\u4e00\u4e2aNotion\u6bb5\u843d\nconst returnItems = [];\n\nparagraphs.forEach((paragraph, index) => {\n  if (paragraph.trim().length > 0) {\n    // \u786e\u4fdd\u6bb5\u843d\u4e0d\u8d85\u8fc72000\u5b57\u7b26\n    if (paragraph.length > 2000) {\n      // \u5982\u679c\u8d85\u8fc7\uff0c\u8fdb\u4e00\u6b65\u5206\u5272\n      let startIdx = 0;\n      while (startIdx < paragraph.length) {\n        const chunk = paragraph.substring(startIdx, Math.min(startIdx + 1900, paragraph.length));\n        returnItems.push({\n          json: {\n            index: returnItems.length,\n            content: chunk,\n            type: \"paragraph\"\n          }\n        });\n        startIdx += 1900;\n      }\n    } else {\n      // \u5982\u679c\u6bb5\u843d\u957f\u5ea6\u5408\u9002\uff0c\u76f4\u63a5\u6dfb\u52a0\n      returnItems.push({\n        json: {\n          index: index,\n          content: paragraph,\n          type: \"paragraph\"\n        }\n      });\n    }\n  }\n});\n\nreturn returnItems;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        2220
      ],
      "id": "9506bc44-cd63-4036-9117-b90f3c0ae659",
      "name": "parse_to_paragraphs"
    },
    {
      "parameters": {
        "jsCode": "return $('parse_to_paragraphs').all().map(item => ({\n  json: {\n    content: item.json.content,\n    type: item.json.type,\n    index: item.json.index\n  }\n}))"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        580,
        2220
      ],
      "id": "9aa6a16e-eb1b-4f0c-80fa-4ddd2901e59e",
      "name": "return_all_items"
    },
    {
      "parameters": {
        "resource": "block",
        "blockId": {
          "__rl": true,
          "value": "={{ $('create_new_cover_letter').item.json.id }}",
          "mode": "id"
        },
        "blockUi": {
          "blockValues": [
            {
              "textContent": "={{ $json.content }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.notion",
      "typeVersion": 2.2,
      "position": [
        760,
        2220
      ],
      "id": "2c177160-fb3d-461d-9692-f336edf9b504",
      "name": "append_blocks",
      "executeOnce": false,
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "value": "1ed2e9a3-326a-8177-8956-c0b5c8378bd9",
          "mode": "list",
          "cachedResultName": "Job Tracker",
          "cachedResultUrl": "https://www.notion.so/1ed2e9a3326a81778956c0b5c8378bd9"
        },
        "title": "={{ $json.company_name }}",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Application URL|url",
              "urlValue": "={{ $json.application_url }}"
            },
            {
              "key": "Flexibility|multi_select",
              "multiSelectValue": "={{ $json.flexibility }}"
            },
            {
              "key": "Industry|rich_text",
              "textContent": "={{ $json.industry }}"
            },
            {
              "key": "Salary Range|rich_text",
              "textContent": "={{ $json.salary_range }}"
            },
            {
              "key": "Status|select",
              "selectValue": "Applied"
            },
            {
              "key": "Location|rich_text",
              "textContent": "={{ $json.location }}"
            },
            {
              "key": "Job Title|rich_text",
              "textContent": "={{ $json.job_title }}"
            }
          ]
        },
        "blockUi": {
          "blockValues": [
            {
              "textContent": "={{ $json.description.substring(0,1998) }}"
            },
            {
              "textContent": "=created at {{ $json.created_at }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.notion",
      "typeVersion": 2.2,
      "position": [
        -1900,
        2220
      ],
      "id": "bb4a25b8-f2f5-477d-af13-2b56de8b04d6",
      "name": "create_new_job_listing",
      "executeOnce": true,
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "value": "1ed2e9a3-326a-809c-8508-f4faad3a019c",
          "mode": "list",
          "cachedResultName": "Cover Letter",
          "cachedResultUrl": "https://www.notion.so/1ed2e9a3326a809c8508f4faad3a019c"
        },
        "title": "=Jiaqi_Wen_ {{ $now.format('yyyy-MM-dd HH:MM') }}",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Company Name|title",
              "title": "={{ $('create_new_job_listing').item.json.property_company_name }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.notion",
      "typeVersion": 2.2,
      "position": [
        400,
        2220
      ],
      "id": "39db0f2b-6270-43a8-93d8-3dc582ff50cf",
      "name": "create_new_cover_letter",
      "executeOnce": true,
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "7385ee1c-5a5e-4576-b311-c6fd3f678a8b",
              "name": "property_company_name",
              "value": "={{ $json.property_company_name }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -1660,
        2220
      ],
      "id": "0cbfcbe5-8579-46be-b855-a5c60bed2636",
      "name": "set_company_name"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "12c45e38-79d5-49d1-92ed-8e1aee3081b6",
              "name": "output",
              "value": "={{ $json.output }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -700,
        2220
      ],
      "id": "5a01466f-ad94-4471-9937-c18289e1b228",
      "name": "set_cover_letter"
    },
    {
      "parameters": {
        "jsCode": "// \u4ece Supabase \u67e5\u8be2\u7ed3\u679c\u4e2d\u63d0\u53d6\u5df2\u5b58\u5728\u7684\u804c\u4f4d ID\n// \u786e\u4fdd\u6240\u6709 ID \u90fd\u8f6c\u6362\u4e3a\u76f8\u540c\u7684\u7c7b\u578b\uff08\u5b57\u7b26\u4e32\uff09\nconst existingJobIds = $('Supabase1').all().map(item => String(item.json.id));\nconsole.log(`\u6570\u636e\u5e93\u4e2d\u5df2\u6709 ${existingJobIds.length} \u4e2a\u804c\u4f4d ID`);\n// \u83b7\u53d6\u65b0\u6293\u53d6\u7684\u804c\u4f4d\u6570\u636e\nconst newJobs = $('Merge').all();\nconsole.log(`\u65b0\u6293\u53d6\u7684\u804c\u4f4d\u6570\u91cf: ${newJobs.length} \u4e2a`);\n// \u8fc7\u6ee4\u6389\u5df2\u5b58\u5728\u7684\u804c\u4f4d - \u540c\u6837\u786e\u4fdd ID \u8f6c\u6362\u4e3a\u76f8\u540c\u7c7b\u578b\u8fdb\u884c\u6bd4\u8f83\nconst uniqueJobs = newJobs.filter(job => !existingJobIds.includes(String(job.json.id)));\nconsole.log(`\u8fc7\u6ee4\u540e\u7684\u4e0d\u91cd\u590d\u804c\u4f4d\u6570\u91cf: ${uniqueJobs.length} \u4e2a`);\n// \u5728 return \u524d\u518d\u6b21\u8fc7\u6ee4 uniqueJobs \u6570\u7ec4\u4e2d\u7684\u91cd\u590d\u503c\nconst finalUniqueJobs = uniqueJobs.filter((job, index, self) => \n  index === self.findIndex(j => String(j.json.id) === String(job.json.id))\n);\nconsole.log(`\u6700\u7ec8\u53bb\u91cd\u540e\u7684\u804c\u4f4d\u6570\u91cf: ${finalUniqueJobs.length} \u4e2a`);\n// \u8fd4\u56de\u4e0d\u91cd\u590d\u7684\u804c\u4f4d\u6570\u636e\nreturn finalUniqueJobs;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1640,
        580
      ],
      "id": "a1c6bea1-932d-4381-a8f8-7c3a0a0eadf7",
      "name": "get_unique_jobs"
    },
    {
      "parameters": {
        "modelName": "models/gemini-2.0-flash-lite-001",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1,
      "position": [
        -1020,
        2440
      ],
      "id": "07500052-1a4b-4d0f-b347-24aac8650882",
      "name": "Google Gemini Chat Model2",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "6c37a80a-a136-4f79-b8c8-056cd044d5c0",
              "name": "runId",
              "value": "={{ $json.data.id }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -520,
        580
      ],
      "name": "Extract Run ID",
      "id": "e4024b46-2576-44b3-b4ec-a49d642a655a"
    },
    {
      "parameters": {
        "url": "=https://api.apify.com/v2/actor-runs/{{ $('Extract Run ID').item.json.runId }}?token={{ $('Input').item.json.ApifyAPIKey }}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -120,
        580
      ],
      "name": "Check Run Status",
      "id": "b020a447-3c83-4abe-9101-332a32f14446"
    },
    {
      "parameters": {
        "conditions": {
          "number": [
            {
              "value1": "={{ $json.data.status }}",
              "operation": "equal",
              "value2": "=SUCCEEDED"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        80,
        580
      ],
      "name": "Check if Succeeded",
      "id": "7dc13011-3cb0-4945-942b-2e3df15f9bc5"
    },
    {
      "parameters": {
        "url": "=https://api.apify.com/v2/actor-runs/{{ $('Extract Run ID').item.json.runId }}/dataset/items?token={{ $('Input').item.json.ApifyAPIKey }}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        280,
        480
      ],
      "name": "Get Dataset Items",
      "id": "08b46bef-3eff-402e-bc09-ad70e4d15cd0"
    },
    {
      "parameters": {
        "amount": "={{ $('Input').first().json.request_interval }}"
      },
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        280,
        680
      ],
      "name": "Wait and Retry",
      "id": "6b420dda-f126-4f32-a492-e71c0d8043bf"
    },
    {
      "parameters": {
        "amount": "={{ $('Input').first().json.first_timeout }}"
      },
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        -320,
        580
      ],
      "name": "Wait 1 Minutes",
      "id": "980a6288-1a93-4a2d-88ce-8bf4fd064872"
    },
    {
      "parameters": {
        "jsCode": "// \u83b7\u53d6\u6240\u6709\u804c\u4f4d\nconst allJobs = $input.all();\nconsole.log(`\u603b\u804c\u4f4d\u6570: ${allJobs.length}`);\n\n// \u8fc7\u6ee4\u51fa\u65b0\u804c\u4f4d\u548c\u672a\u5904\u7406\u804c\u4f4d\nconst jobsForProcessing = allJobs.filter(item => {\n  const job = item.json;\n  // \u9009\u62e9'new'\u72b6\u6001\u6216\u65e0\u72b6\u6001\u7684\u804c\u4f4d\n  return job.status === 'new' || job.status === null || job.status === undefined;\n});\n\nconsole.log(`\u8fc7\u6ee4\u540e\u5f85\u5904\u7406\u804c\u4f4d\u6570: ${jobsForProcessing.length}`);\n\n// \u5982\u679c\u6ca1\u6709\u65b0\u804c\u4f4d\uff0c\u6dfb\u52a0\u4e00\u4e2a\u65e5\u5fd7\u6d88\u606f\nif (jobsForProcessing.length === 0) {\n  console.log('\u6ca1\u6709\u65b0\u804c\u4f4d\u9700\u8981\u5904\u7406');\n}\n\nreturn jobsForProcessing;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1440,
        580
      ],
      "id": "cb23b816-4d97-4a35-84e8-6cac1999f011",
      "name": "filter_by_status"
    },
    {
      "parameters": {
        "jsCode": "// \u5728n8n\u7684Function\u8282\u70b9\u4e2d\nlet jobListingsHTML = '';\nlet jobs;\n\n// \u5c1d\u8bd5\u591a\u79cd\u53ef\u80fd\u7684\u6570\u636e\u7ed3\u6784\ntry {\n  if ($input.item && $input.item[0] && $input.item[0].json && $input.item[0].json.output) {\n    jobs = $input.item[0].json.output;\n  } else if ($input.all()[0].json.output) {\n    jobs = $input.all()[0].json.output;\n  } else if ($input.first().json[0] && $input.first().json[0].output) {\n    jobs = $input.first().json[0].output;\n  } else {\n    // \u53ef\u80fd\u6570\u636e\u5728\u66f4\u6df1\u7684\u5d4c\u5957\u4e2d\n    jobs = $input.first().json;\n    if (Array.isArray(jobs) && jobs[0] && jobs[0].output) {\n      jobs = jobs[0].output;\n    }\n  }\n} catch (error) {\n  // \u6570\u636e\u7ed3\u6784\u95ee\u9898\u65f6\u7684\u5907\u9009\u65b9\u6848\n  jobs = [];\n  console.log('Error accessing job data:', error.message);\n}\n\n// \u5982\u679cjobs\u8fd8\u4e0d\u662f\u6570\u7ec4\uff0c\u5c1d\u8bd5\u6700\u540e\u7684\u65b9\u6cd5\nif (!Array.isArray(jobs)) {\n  console.log('Jobs is not an array, trying alternative method');\n  // \u6253\u5370\u51fa\u5b9e\u9645\u6570\u636e\u7ed3\u6784\u4ee5\u4fbf\u8c03\u8bd5\n  console.log('Actual data structure:', JSON.stringify($input.all()));\n  jobs = [];\n}\n\n// \u751f\u6210HTML...\n// \u4e3a\u6bcf\u4e2a\u5de5\u4f5c\u673a\u4f1a\u521b\u5efaHTML\njobs.forEach(job => {\n  jobListingsHTML += `\n    <!-- Job for ${job['Company Name']} -->\n    <tr>\n        <td style=\"padding: 0 25px;\">\n            <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"border: 1px solid #dce3ea; border-radius: 10px; margin-bottom: 25px; overflow: hidden;\">\n                <tr>\n                    <td style=\"background-color: #4a6fa5; color: #ffffff; padding: 18px 20px;\">\n                        <strong style=\"font-size: 18px;\">${job['Company Name']}</strong><br>\n                        <span style=\"font-size: 14px; opacity: 0.9;\">${job['Job Title']}</span>\n                    </td>\n                </tr>\n                <tr>\n                    <td style=\"padding: 20px; background-color: #ffffff;\">\n                        <div style=\"display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px;\">\n                            <div style=\"background-color: #eef2f7; color: #4a6fa5; border-radius: 20px; padding: 8px 14px; font-size: 13px; display: inline-block;\">${job.Industry}</div>\n                            <div style=\"background-color: #f0f7f4; color: #00a06a; border-radius: 20px; padding: 8px 14px; font-size: 13px; display: inline-block;\">${job.Flexibility}</div>\n                            <div style=\"background-color: #f7f4f0; color: #a06a00; border-radius: 20px; padding: 8px 14px; font-size: 13px; display: inline-block;\">${job['Salary Range']}</div>\n                        </div>\n                        \n                        <div style=\"margin-bottom: 12px; background-color: #fafafa; padding: 12px; border-radius: 6px;\">\n                            <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n                                <tr>\n                                    <td style=\"padding-bottom: 8px;\">\n                                        <span style=\"font-size: 13px; color: #666666;\">\ud83d\udccd Location:</span>\n                                        <span style=\"font-size: 13px; color: #333333; font-weight: bold; margin-left: 4px;\">${job.Location}</span>\n                                    </td>\n                                </tr>\n                            </table>\n                        </div>\n                        \n                        <div style=\"margin-bottom: 18px; border-left: 4px solid #4a6fa5; padding-left: 14px; background-color: #f9f9f9; padding-top: 10px; padding-bottom: 10px;\">\n                            <strong style=\"color: #2a5298; font-size: 15px;\">Why this matches your profile:</strong>\n                            <p style=\"font-size: 13px; color: #444444; margin: 10px 0 0;\">${job['Reason for Match']}</p>\n                        </div>\n\n                        <a href=\"${job['Application URL']}\" target=\"_blank\" style=\"display: inline-block; background-color: #00c07f; color: #ffffff; text-decoration: none; padding: 12px 24px; font-size: 14px; font-weight: bold; border-radius: 6px;\">Apply Now</a>\n                        <div style=\"display: flex; margin-top: 15px;\">\n                            <a href=\"http://localhost:5678/webhook/2f32a889-c6d8-4dda-a550-71d963063aa7?jobId=${job['database_id']}\" target=\"_blank\" style=\"display: inline-block; background-color: #4a6fa5; color: #ffffff; text-decoration: none; padding: 8px 16px; font-size: 12px; border-radius: 4px;\">Generate Cover Letter</a>\n                        </div>\n                    </td>\n                </tr>\n            </table>\n        </td>\n    </tr>\n  `;\n});\n\n// \u5728\u4f60\u539f\u59cb\u7684HTML\u6a21\u677f\u4e2d\u66ff\u6362\u6389\u5355\u4e2a\u5de5\u4f5c\u9879\u7684\u90e8\u5206\nconst fullHTML = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Your Tailored Career Opportunities</title>\n</head>\n<body style=\"font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; line-height: 1.6; color: #333333; background-color: #f5f7fa; margin: 0; padding: 0;\">\n    <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n        <tr>\n            <td align=\"center\" style=\"padding: 30px 15px;\">\n                <table width=\"600\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"background-color: #ffffff; border-collapse: collapse; box-shadow: 0 0 12px rgba(0,0,0,0.05); border-radius: 8px; overflow: hidden;\">\n                    <tr>\n                        <td style=\"background-color: #2a5298; color: #ffffff; padding: 40px 30px; text-align: center;\">\n                            <h1 style=\"margin: 0; font-size: 24px; font-weight: bold;\">Your Personalized Career Opportunities</h1>\n                            <p style=\"margin: 15px 0 0; font-size: 15px; opacity: 0.9;\">Handpicked opportunities aligned with your expertise and preferences</p>\n                        </td>\n                    </tr>\n\n                    <tr><td height=\"30\"></td></tr>\n\n                    ${jobListingsHTML}\n\n                </table>\n            </td>\n        </tr>\n    </table>\n</body>\n</html>`;\n\n// \u8fd4\u56de\u6b63\u786e\u683c\u5f0f\nreturn [{json: {html: fullHTML}}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3740,
        560
      ],
      "id": "ce73e0d7-28ec-4001-98ed-11a82f954279",
      "name": "generate_html_template"
    },
    {
      "parameters": {
        "jsCode": "// \u83b7\u53d6AI\u5339\u914d\u540e\u7684\u804c\u4f4d\nlet matchedJobs = [];\nconsole.log('t')\n\ntry {\n  // \u5c1d\u8bd5\u4ece\u4e0d\u540c\u53ef\u80fd\u7684\u4f4d\u7f6e\u83b7\u53d6\u5339\u914d\u7684\u804c\u4f4d\n  if ($input.first().json.output && Array.isArray($input.first().json.output)) {\n    matchedJobs = $input.first().json.output;\n  } else if ($input.first().json && Array.isArray($input.first().json)) {\n    matchedJobs = $input.first().json;\n  } else {\n    console.log('\u65e0\u6cd5\u627e\u5230\u5339\u914d\u7684\u804c\u4f4d\u6570\u636e\uff0c\u68c0\u67e5\u8f93\u5165\u683c\u5f0f');\n    console.log('\u8f93\u5165\u6570\u636e:', JSON.stringify($input.first().json));\n  }\n} catch (error) {\n  console.error('\u89e3\u6790\u5339\u914d\u804c\u4f4d\u65f6\u51fa\u9519:', error.message);\n}\n\nconsole.log(`\u627e\u5230 ${matchedJobs.length} \u4e2a\u5339\u914d\u7684\u804c\u4f4d`);\n\n// \u51c6\u5907\u8981\u66f4\u65b0\u7684\u804c\u4f4dID\u5217\u8868\nconst jobIdsToUpdate = matchedJobs.map(job => job.database_id || job.id);\nconsole.log('\u8981\u66f4\u65b0\u7684\u804c\u4f4dID:', jobIdsToUpdate);\n\n// \u51c6\u5907\u8981\u4fdd\u5b58\u5230Supabase\u7684\u6570\u636e\nconst updateOperations = [];\nfor (const id of jobIdsToUpdate) {\n  if (id) {\n    updateOperations.push({\n      json: {\n        id: id,\n        status: 'processed',\n        processed_at: new Date().toISOString()\n      }\n    });\n  }\n}\n\n// \u4fdd\u5b58\u539f\u59cb\u5339\u914d\u7ed3\u679c\uff0c\u4ee5\u4fbf\u540e\u7eed\u6d41\u7a0b\u4f7f\u7528\nconst originalData = $input.first().json;\n\n// \u8fd4\u56de\u5305\u542b\u539f\u59cb\u6570\u636e\u548c\u66f4\u65b0\u64cd\u4f5c\u7684\u590d\u5408\u5bf9\u8c61\nreturn {\n  json: {\n    matchedJobs: originalData,\n    updateOperations: updateOperations\n  }\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3200,
        560
      ],
      "id": "15e09766-5173-4ae4-bdcb-307bb1eb8463",
      "name": "update_job_status"
    },
    {
      "parameters": {
        "content": "### Supabase / Supabase1\n\u5c06\u722c\u53d6\u7684\u804c\u4f4d\u6570\u636e\u5b58\u50a8\u5230Supabase\u6570\u636e\u5e93\u4e2d\uff0c\u7528\u4e8e\u6301\u4e45\u5316\u5b58\u50a8\u548c\u53bb\u91cd\u3002\n\u786e\u4fdd\u4e0d\u91cd\u590d\u5904\u7406\u540c\u4e00\u804c\u4f4d\u4fe1\u606f\u3002\n\n### filter_by_status / get_unique_jobs\n\u8fc7\u6ee4\u51fa\u65b0\u7684\u3001\u672a\u5904\u7406\u8fc7\u7684\u804c\u4f4d\u4fe1\u606f\uff0c\u5e76\u786e\u4fdd\u804c\u4f4dID\u7684\u552f\u4e00\u6027\u3002",
        "height": 640,
        "width": 920,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1140,
        280
      ],
      "id": "49900548-3976-4a2c-bd9d-f4b4fc1fd335",
      "name": "Sticky Note8"
    },
    {
      "parameters": {
        "content": "### start_apify_run_indeed\n\u542f\u52a8Apify\u722c\u866b\uff0c\u6293\u53d6LinkedIn\u4e0a\u7684\u804c\u4f4d\u4fe1\u606f\u3002\n\u786e\u4fdd\u5728jsonBody\u4e2d\u8bbe\u7f6e\u6b63\u786e\u7684\u641c\u7d22URL\u548c\u53c2\u6570\u3002\n\n### Check Run Status / Get Dataset Items\n\u8fd9\u4e9b\u8282\u70b9\u68c0\u67e5\u722c\u866b\u8fd0\u884c\u72b6\u6001\u5e76\u83b7\u53d6\u7ed3\u679c\u6570\u636e\u3002\n\u5305\u542b\u9519\u8bef\u5904\u7406\u548c\u91cd\u8bd5\u673a\u5236\uff0c\u786e\u4fdd\u53ef\u9760\u83b7\u53d6\u804c\u4f4d\u4fe1\u606f\u3002\n",
        "height": 660,
        "width": 1280,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -800,
        1020
      ],
      "id": "c3e70cdb-90ef-44bb-bc9e-90cb9d8ed2ba",
      "name": "Sticky Note12"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "6c37a80a-a136-4f79-b8c8-056cd044d5c0",
              "name": "runId",
              "value": "={{ $json.data.id }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -520,
        1340
      ],
      "name": "Extract Run ID1",
      "id": "743c0c6a-08bd-4d82-b38c-ba4a01fc48bf"
    },
 

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

How this works

This workflow automates your LinkedIn job search by scanning for roles that match your skills and experience, then generates personalised cover letters to boost your application success rate. It's ideal for professionals actively hunting for new opportunities who want to save hours on manual research and writing. The key step involves an AI agent analysing your uploaded resume from Google Drive to identify the best-matched jobs on LinkedIn, followed by crafting tailored cover letters using Google Gemini.

Use this workflow when you're job hunting regularly and need consistent, high-quality applications without repetitive effort, such as during a career transition. Avoid it if you're targeting niche roles requiring deep customisation beyond AI capabilities or if you prefer full manual control over every detail. Common variations include adding Gmail integration to send applications directly or adjusting the schedule trigger for daily versus weekly runs.

About this workflow

LinkedIn_Job_Hunt_and_Cover_Letter. Uses outputParserStructured, outputParserAutofixing, googleDrive, agent. Scheduled trigger; 85 nodes.

Source: https://github.com/wenjiaqi8255/n8n-workflow/blob/144b48cf3c4352f707600329d5dffba5b638ad5d/LinkedIn_Job_Hunt_and_Cover_Letter_By_Wen.json — 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

kisisel asistan. Uses toolWorkflow, toolHttpRequest, toolCalculator, toolThink. Scheduled trigger; 43 nodes.

Tool Workflow, Tool Http Request, Tool Calculator +15
AI & RAG

This n8n template automates the tedious process of searching for jobs on LinkedIn. By integrating with tools for web scraping and leveraging AI (Google Gemini) for intelligent matching, this workflow

Output Parser Structured, Output Parser Autofixing, Google Drive +4
AI & RAG

AI powered workflow that scans HR news via RSS, checks which of your policies or contract templates might need updates, and sends a weekly internal newsletter as HTML.

RSS Feed Read, HTTP Request, Google Drive +5
AI & RAG

This n8n automation workflow automates the creation, scripting, production, and posting of YouTube videos. It leverages AI (OpenAI), image generation (PIAPI), video rendering (Shotstack), and platform

Agent, OpenAI Chat, Airtable Tool +7
AI & RAG

Who is this for? Agencies, consultants, and service providers who conduct discovery calls and need to quickly turn conversations into professional proposals.

Tool Think, Tool Calculator, Agent Tool +18