AutomationFlowsAI & RAG › Screen Candidates and Send Take-home Assignments with Google Sheets, Gmail,…

Screen Candidates and Send Take-home Assignments with Google Sheets, Gmail,…

Original n8n title: Screen Candidates and Send Take-home Assignments with Google Sheets, Gmail, Anthropic, and Openai

ByNocode Expert @iamrup on n8n.io

This workflow pulls candidates from Google Sheets, uses an Anthropic-powered AI agent with an in-memory vector-store rubric (RAG) to score and shortlist applicants, writes results back to the sheet, then emails a take-home assignment via Gmail to candidates who are marked as…

Event trigger★★★★☆ complexityAI-powered21 nodesDocument Default Data LoaderOpenAI EmbeddingsIn-Memory Vector StoreGoogle SheetsAnthropic ChatOutput Parser StructuredAgentGmail
AI & RAG Trigger: Event Nodes: 21 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Agent → Documentdefaultdataloader 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": "09recruit0000001",
  "name": "Screen candidates from Google Sheets and email a take-home assignment with AI",
  "tags": [],
  "nodes": [
    {
      "id": "overview",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2016,
        112
      ],
      "parameters": {
        "width": 1060,
        "height": 704,
        "content": "## AI candidate screener \u2192 take-home assignment\n\nScreen applicants for a Performance Marketing role against an expert rubric, then email the take-home only to the ones a human approves.\n\n### How it works\n- Reads applicants from a Google Sheet (name, email, resume text, answers).\n- Loads the screening rubric into an in-memory vector store (RAG), so scoring is grounded in real criteria, not vibes.\n- An AI Agent retrieves the rubric and scores each candidate 1-5 per competency, computes a weighted total, and flags shortlist yes/no with strengths and gaps.\n- Writes scores back to the Sheet marked SHORTLISTED_PENDING_APPROVAL.\n- After you approve the shortlist in the Sheet, the approved candidates are emailed the take-home assignment.\n\n### Setup\n1. Add credentials in the canvas: an LLM (OpenAI or Anthropic) + embeddings, Google Sheets, Gmail.\n2. Point the Sheet nodes at your applicants sheet; set the shortlist threshold in the config node.\n3. Edit the rubric and assignment text to your role.\n\n### Responsible use\nHuman approves before any candidate is emailed and makes the final call. The rubric forbids using protected attributes; scoring is explainable.\n\nBuilt by **nocode.expert** \u2014 done-for-you automation & AI workflows. https://nocode.expert"
      },
      "typeVersion": 1
    },
    {
      "id": "section-rag-rubric",
      "name": "Section: RAG rubric",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -192,
        272
      ],
      "parameters": {
        "color": 7,
        "width": 664,
        "height": 396,
        "content": "## 1. Load rubric (RAG)\nPut the screening rubric in an in-memory vector store so scoring is grounded in real criteria."
      },
      "typeVersion": 1
    },
    {
      "id": "section-score-candidates",
      "name": "Section: Score candidates",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        688,
        272
      ],
      "parameters": {
        "color": 7,
        "width": 812,
        "height": 396,
        "content": "## 2. Score each candidate\nAI Agent retrieves the rubric and scores each applicant (structured output). Swap the model for OpenAI if you prefer."
      },
      "typeVersion": 1
    },
    {
      "id": "section-approve-send",
      "name": "Section: Approve & send",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1552,
        272
      ],
      "parameters": {
        "color": 7,
        "width": 1036,
        "height": 396,
        "content": "## 3. Approve \u2192 send\nWrite scores to the Sheet, you approve the shortlist, then email the take-home to approved candidates."
      },
      "typeVersion": 1
    },
    {
      "id": "run-manually",
      "name": "Run manually",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -768,
        464
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "set-config-rubric",
      "name": "Set config + rubric",
      "type": "n8n-nodes-base.set",
      "position": [
        -480,
        464
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a1",
              "name": "rubricText",
              "type": "string",
              "value": "PERFORMANCE MARKETING \u2014 CANDIDATE SCREENING RUBRIC\n\nScore each competency 1-5 (5=exceptional). Shortlist only if weighted score >= threshold AND all MUST-HAVES are met.\n\n1. PAID MEDIA EXECUTION (weight 30%) \u2014 Hands-on build/optimize/scale on Meta and Google (TikTok a plus). Evidence of managing real budgets, not just dashboards. MUST-HAVE: has personally run paid campaigns end to end.\n2. MEASUREMENT & TRACKING (weight 25%) \u2014 Understands attribution, server-side conversions/CAPI, ROAS/CAC/MER, and why platform-reported numbers lie. MUST-HAVE: can explain how they verify a conversion is real.\n3. TESTING & CREATIVE (weight 20%) \u2014 Hypothesis-driven testing, structured creative iteration, reads results without fooling themselves. \n4. SCALING & BUDGET JUDGMENT (weight 15%) \u2014 Knows how to scale efficiently and when to cut; treats spend as their own money.\n5. OWNERSHIP & COMMUNICATION (weight 10%) \u2014 Clear reporting, takes accountability for outcomes, explains tradeoffs simply.\n\nRED FLAGS: only agency-side reporting with no execution; conflates clicks/impressions with conversions; no measurement rigor; blames platforms for everything.\nDo NOT consider or infer any protected attribute (age, gender, race, nationality, etc.). Score only on evidence of competency."
            },
            {
              "id": "a2",
              "name": "threshold",
              "type": "string",
              "value": "70"
            },
            {
              "id": "a3",
              "name": "assignmentSubject",
              "type": "string",
              "value": "Take-home for the Performance Marketing role"
            },
            {
              "id": "a4",
              "name": "assignmentBrief",
              "type": "string",
              "value": "Using the sample account data attached, identify the 3 biggest opportunities, write a 1-week action plan, and propose a measurement setup you would trust. Keep it under 2 hours. Reply to this email with your submission."
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "rubric-document-loader",
      "name": "Rubric document loader",
      "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
      "position": [
        432,
        1056
      ],
      "parameters": {
        "options": {},
        "jsonData": "={{ $json.rubricText }}",
        "jsonMode": "expressionData"
      },
      "typeVersion": 1.1
    },
    {
      "id": "embeddings",
      "name": "Embeddings",
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "position": [
        -80,
        1264
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "load-rubric-into-vector-store",
      "name": "Load rubric into vector store",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreInMemory",
      "position": [
        -160,
        464
      ],
      "parameters": {
        "mode": "insert",
        "memoryKey": "pm_screening_rubric"
      },
      "typeVersion": 1.1
    },
    {
      "id": "get-candidates-from-google-sheet",
      "name": "Get candidates from Google Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        208,
        464
      ],
      "parameters": {
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "rubric-retriever-tool",
      "name": "Rubric retriever (tool)",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreInMemory",
      "position": [
        1136,
        1152
      ],
      "parameters": {
        "mode": "retrieve-as-tool",
        "toolName": "pm_rubric",
        "memoryKey": "pm_screening_rubric",
        "toolDescription": "The performance marketing screening rubric and scoring criteria"
      },
      "typeVersion": 1.1
    },
    {
      "id": "anthropic-chat-model",
      "name": "Anthropic Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        720,
        896
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultUrl": "",
          "cachedResultName": ""
        },
        "options": {}
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "structured-score-parser",
      "name": "Structured score parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1376,
        976
      ],
      "parameters": {
        "jsonSchemaExample": "{\"weighted_total\":82,\"shortlist\":true,\"strengths\":[\"ran real Meta budgets\",\"explains CAPI verification\"],\"gaps\":[\"light on TikTok\"]}"
      },
      "typeVersion": 1.2
    },
    {
      "id": "score-candidate-vs-rubric",
      "name": "Score candidate vs rubric",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        864,
        464
      ],
      "parameters": {
        "text": "You are screening a candidate for a Performance Marketing role. Use the pm_rubric tool to retrieve the scoring criteria, then evaluate ONLY the candidate evidence below against it.\nScore each of the 5 competencies 1-5 with a one-line justification, compute the weighted total (0-100), decide shortlist true/false (must-haves met AND weighted >= threshold), and list up to 3 strengths and 3 gaps.\nNever infer or use protected attributes. Be specific and terse.\n\nCandidate: {{ $json.name }} <{{ $json.email }}>\nResume: {{ $json.resume_text }}\nApplication answers: {{ $json.answers }}\nShortlist threshold: {{ $('Set config + rubric').first().json.threshold }}",
        "options": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.9
    },
    {
      "id": "flatten-scores-for-sheet",
      "name": "Flatten scores for Sheet",
      "type": "n8n-nodes-base.code",
      "position": [
        1280,
        464
      ],
      "parameters": {
        "jsCode": "// Normalize the agent's structured output into flat columns for the Sheet.\nconst candidates = $('Get candidates from Google Sheet').all();\nconst items = $input.all();\nconst out = [];\nfor (let i = 0; i < items.length; i++) {\n  const j = items[i].json;\n  const r = j.output || j; // agent output may be nested\n  const cand = (candidates[i] && candidates[i].json) || {};\n  out.push({ json: {\n    name: cand.name,\n    email: cand.email,\n    weighted_score: r.weighted_total ?? r.score ?? null,\n    shortlist: !!r.shortlist,\n    strengths: Array.isArray(r.strengths) ? r.strengths.join('; ') : (r.strengths || ''),\n    gaps: Array.isArray(r.gaps) ? r.gaps.join('; ') : (r.gaps || ''),\n    status: r.shortlist ? 'SHORTLISTED_PENDING_APPROVAL' : 'REJECTED',\n  } });\n}\nreturn out;"
      },
      "typeVersion": 2
    },
    {
      "id": "write-scores-back-to-sheet",
      "name": "Write scores back to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1696,
        464
      ],
      "parameters": {
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "get-approved-shortlist",
      "name": "Get approved shortlist",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2128,
        464
      ],
      "parameters": {
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "email-the-take-home-assignment",
      "name": "Email the take-home assignment",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2864,
        192
      ],
      "parameters": {
        "sendTo": "={{ $json.email }}",
        "message": "=Hi {{ $json.name }},\n\n{{ $('Set config + rubric').first().json.assignmentBrief }}\n\nThanks!",
        "options": {},
        "subject": "={{ $('Set config + rubric').first().json.assignmentSubject }}"
      },
      "typeVersion": 2.1
    },
    {
      "id": "c9c02279-dee1-4694-8169-4cff40cf2c73",
      "name": "Switch",
      "type": "n8n-nodes-base.switch",
      "position": [
        2384,
        464
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Shortlisted",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "1e2b599d-0aa0-471b-a599-a097b947156d",
                    "operator": {
                      "type": "string",
                      "operation": "notEquals"
                    },
                    "leftValue": "={{ $json.status }}",
                    "rightValue": "REJECTED"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Not Shortlisted",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "8c5840a0-ba2f-41d7-b998-4df1be571e8d",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.status }}",
                    "rightValue": "REJECTED"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "tpBgHHbxFDn722Pt",
      "name": "Fix score format",
      "type": "@n8n/n8n-nodes-langchain.outputParserAutofixing",
      "position": [
        1328,
        800
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "4ad937a5-8b5f-4131-a8b4-4dca8f072196",
      "name": "Human evaluation",
      "type": "n8n-nodes-base.gmail",
      "disabled": true,
      "position": [
        2880,
        640
      ],
      "parameters": {
        "sendTo": "={{ $json.email }}",
        "message": "=Hi {{ $json.name }},\n\n{{ $('Set config + rubric').first().json.assignmentBrief }}\n\nThanks!",
        "options": {},
        "subject": "={{ $('Set config + rubric').first().json.assignmentSubject }}"
      },
      "typeVersion": 2.1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "24077f86-3f28-46ea-a1f7-c57b696b189c",
  "nodeGroups": [],
  "connections": {
    "Switch": {
      "main": [
        [
          {
            "node": "Email the take-home assignment",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Human evaluation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Embeddings": {
      "ai_embedding": [
        [
          {
            "node": "Load rubric into vector store",
            "type": "ai_embedding",
            "index": 0
          },
          {
            "node": "Rubric retriever (tool)",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "Run manually": {
      "main": [
        [
          {
            "node": "Set config + rubric",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fix score format": {
      "ai_outputParser": [
        [
          {
            "node": "Score candidate vs rubric",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Set config + rubric": {
      "main": [
        [
          {
            "node": "Load rubric into vector store",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Anthropic Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Score candidate vs rubric",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Fix score format",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Get approved shortlist": {
      "main": [
        [
          {
            "node": "Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rubric document loader": {
      "ai_document": [
        [
          {
            "node": "Load rubric into vector store",
            "type": "ai_document",
            "index": 0
          }
        ]
      ]
    },
    "Rubric retriever (tool)": {
      "ai_tool": [
        [
          {
            "node": "Score candidate vs rubric",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Structured score parser": {
      "ai_outputParser": [
        [
          {
            "node": "Fix score format",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Flatten scores for Sheet": {
      "main": [
        [
          {
            "node": "Write scores back to Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Score candidate vs rubric": {
      "main": [
        [
          {
            "node": "Flatten scores for Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Write scores back to Sheet": {
      "main": [
        [
          {
            "node": "Get approved shortlist",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Load rubric into vector store": {
      "main": [
        [
          {
            "node": "Get candidates from Google Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get candidates from Google Sheet": {
      "main": [
        [
          {
            "node": "Score candidate vs rubric",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

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

Pro

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

About this workflow

This workflow pulls candidates from Google Sheets, uses an Anthropic-powered AI agent with an in-memory vector-store rubric (RAG) to score and shortlist applicants, writes results back to the sheet, then emails a take-home assignment via Gmail to candidates who are marked as…

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

Inquiry-Agent. Uses @digitalocean/n8n-nodes-digitalocean-gradient-serverless-inference, stopAndError, googleDocs, gmail. Event-driven trigger; 88 nodes.

@Digitalocean/N8N Nodes Digitalocean Gradient Serverless Inference, Stop And Error, Google Docs +12
AI & RAG

Alfred (funcional). Uses gmailTool, googleCalendarTool, gmail, embeddingsOpenAi. Event-driven trigger; 83 nodes.

Gmail Tool, Google Calendar Tool, Gmail +24
AI & RAG

Inquiry-Agent. Uses @digitalocean/n8n-nodes-digitalocean-gradient-serverless-inference, stopAndError, googleDocs, gmail. Event-driven trigger; 80 nodes.

@Digitalocean/N8N Nodes Digitalocean Gradient Serverless Inference, Stop And Error, Google Docs +11
AI & RAG

Inquiry-Agent. Uses @digitalocean/n8n-nodes-digitalocean-gradient-serverless-inference, stopAndError, googleDocs, gmail. Event-driven trigger; 77 nodes.

@Digitalocean/N8N Nodes Digitalocean Gradient Serverless Inference, Stop And Error, Google Docs +10
AI & RAG

Inquiry-Agent. Uses @digitalocean/n8n-nodes-digitalocean-gradient-serverless-inference, stopAndError, googleDocs, gmail. Event-driven trigger; 73 nodes.

@Digitalocean/N8N Nodes Digitalocean Gradient Serverless Inference, Stop And Error, Google Docs +9