{
  "name": "Inbox Triage Assistant (Helm Systems)",
  "nodes": [
    {
      "parameters": {
        "content": "## Inbox Triage Assistant\n1. Fill in **Settings**. Connect Gmail, Google Sheets and the AI model credentials.\n2. Every 10 minutes it reads new unread mail in your Primary tab, decides what it is and how urgent, and logs it to a sheet: Date, From, Subject, Category, Urgency, Summary.\n3. When someone is waiting on an answer, it saves a **draft reply in the same thread**. It never sends anything. Prices, dates and commitments are left in [BRACKETS] for you.\n4. Urgent mail triggers an email to you.\n5. Want labels too? Add a Gmail \"Add label\" step after **Read the triage**. Label IDs are specific to your account, so it can't be pre-filled.\nMade by Helm Systems: helmsystems.biz/field-kit",
        "width": 420,
        "height": 330,
        "color": 4
      },
      "id": "fc07f2fa-f527-4ccd-a161-ba21a945726c",
      "name": "Note 1",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        -380
      ]
    },
    {
      "parameters": {
        "pollTimes": {
          "item": [
            {
              "mode": "everyX",
              "value": 10,
              "unit": "minutes"
            }
          ]
        },
        "simple": false,
        "filters": {
          "readStatus": "unread",
          "q": "category:primary",
          "includeDrafts": false,
          "includeSpamTrash": false
        },
        "options": {}
      },
      "id": "7639e504-b7a1-4d44-aefb-6c92c9933e75",
      "name": "Gmail Trigger",
      "type": "n8n-nodes-base.gmailTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "394b3e8b-ea64-401f-aa14-9b2e9c9a60b0",
              "name": "business",
              "value": "Your Business Name",
              "type": "string"
            },
            {
              "id": "59af66ec-940c-4f56-ab43-08c23457a4a5",
              "name": "owner",
              "value": "Your Name",
              "type": "string"
            },
            {
              "id": "2b4c3d53-4e5d-4967-acb0-ad9df0578a60",
              "name": "ownerEmail",
              "value": "you@yourbusiness.com",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "210708f3-9b33-41c8-a129-fa0534615b1b",
      "name": "Settings",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        260,
        0
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const s = $('Settings').first().json;\nconst m = $('Gmail Trigger').item.json;\nreturn { json: {\n  from: m.from?.text || '',\n  fromAddress: m.from?.value?.[0]?.address || '',\n  subject: m.subject || '(no subject)',\n  body: String(m.text || m.snippet || '').slice(0, 3000),\n  threadId: m.threadId || '',\n  business: s.business,\n} };"
      },
      "id": "a0ab7740-2c2e-4c02-ae85-4371dca45df9",
      "name": "Shape",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        520,
        0
      ]
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=From: {{ $json.from }}\nSubject: {{ $json.subject }}\nMessage:\n{{ $json.body }}\n\nReturn JSON with the keys: category, urgency, needs_reply (true or false), summary (one sentence), draft_reply (a string, empty if not needed).",
        "hasOutputParser": false,
        "messages": {
          "messageValues": [
            {
              "message": "=You triage email for the owner of {{ $json.business }}.\n\nCategories: new_lead, customer_question, invoice_or_bill, scheduling, vendor_or_sales, newsletter_or_spam, other.\nUrgency: \"urgent\" (needs a reply today), \"normal\", or \"low\".\n\nRules:\n- needs_reply is true only if a person is waiting on an answer.\n- Write draft_reply only when needs_reply is true and the category is new_lead, customer_question or scheduling. Under 100 words.\n- In the draft, put anything you cannot know (prices, availability, dates) in [SQUARE BRACKETS] for the owner to fill in. Never confirm a price, a time or a commitment.\nReturn only JSON."
            }
          ]
        }
      },
      "id": "71d2a2dd-0649-478f-ab68-bea100e5392f",
      "name": "Triage the email",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.7,
      "position": [
        780,
        0
      ]
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-5-mini",
          "mode": "list",
          "cachedResultName": "gpt-5-mini"
        },
        "options": {}
      },
      "id": "ce79fec3-9dce-4391-aaa2-fcee93493133",
      "name": "Triage the email model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.2,
      "position": [
        780,
        266
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const raw = String($json.text ?? '').trim().replace(/^```(?:json)?/i, '').replace(/```$/, '').trim();\nlet out = {};\nlet ok = true;\ntry { out = JSON.parse(raw); } catch (e) { ok = false; }\nconst needs = [\"category\",\"urgency\",\"needs_reply\",\"summary\"];\nif (ok && !needs.every((k) => out[k] !== undefined && out[k] !== null)) ok = false;\nconst base = $('Shape').item.json;\n\nif (!ok) {\n  out = { ...out, subject: out.subject || 'Check this one: the AI reply could not be read', body: out.body || ('Original AI output:\\n' + raw) };\n}\nreturn { json: { ...base, ...out, canSend: ok } };"
      },
      "id": "c31c57ee-8102-4c39-a049-827c322fa501",
      "name": "Read the triage",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1040,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "afe6cea2-9041-457d-a893-08a6781b0cf5",
              "leftValue": "={{ $json.canSend && $json.needs_reply === true && Boolean($json.draft_reply) && Boolean($json.fromAddress) }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "2e429748-e4a1-41f7-a689-14aff787966c",
      "name": "Is someone waiting?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1300,
        152
      ]
    },
    {
      "parameters": {
        "resource": "draft",
        "operation": "create",
        "subject": "={{ /^re:/i.test($json.subject) ? $json.subject : 'Re: ' + $json.subject }}",
        "emailType": "text",
        "message": "={{ $json.draft_reply }}",
        "options": {
          "sendTo": "={{ $json.fromAddress }}",
          "threadId": "={{ $json.threadId }}"
        }
      },
      "id": "0ede4418-d135-4c28-a81e-660b519bdff6",
      "name": "Save a draft reply",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        1560,
        152
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Date": "={{ $now.toFormat('yyyy-LL-dd') }}",
            "From": "={{ $json.from }}",
            "Subject": "={{ $json.subject }}",
            "Category": "={{ $json.category }}",
            "Urgency": "={{ $json.urgency }}",
            "Summary": "={{ $json.summary }}"
          },
          "matchingColumns": [],
          "schema": []
        },
        "options": {}
      },
      "id": "4eab6549-2d3d-44bd-ad66-1ad1d2bec223",
      "name": "Log it",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        1300,
        -171
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "dc44aa9b-539b-40a2-afa3-4b5883c90ec9",
              "leftValue": "={{ $json.urgency }}",
              "rightValue": "urgent",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "f76d2540-1398-441d-a769-18ec18341ff8",
      "name": "Urgent?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1300,
        380
      ]
    },
    {
      "parameters": {
        "resource": "message",
        "operation": "send",
        "sendTo": "={{ $('Settings').first().json.ownerEmail }}",
        "subject": "={{ 'Urgent: ' + $json.subject }}",
        "emailType": "text",
        "message": "={{ 'From ' + $json.from + '\\n\\n' + $json.summary }}",
        "options": {
          "appendAttribution": false
        }
      },
      "id": "277fcc5e-a3c0-4fa1-a70e-98729949c554",
      "name": "Alert me",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        1560,
        380
      ]
    }
  ],
  "connections": {
    "Triage the email model": {
      "ai_languageModel": [
        [
          {
            "node": "Triage the email",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Gmail Trigger": {
      "main": [
        [
          {
            "node": "Settings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Settings": {
      "main": [
        [
          {
            "node": "Shape",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Shape": {
      "main": [
        [
          {
            "node": "Triage the email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Triage the email": {
      "main": [
        [
          {
            "node": "Read the triage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read the triage": {
      "main": [
        [
          {
            "node": "Is someone waiting?",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log it",
            "type": "main",
            "index": 0
          },
          {
            "node": "Urgent?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is someone waiting?": {
      "main": [
        [
          {
            "node": "Save a draft reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Urgent?": {
      "main": [
        [
          {
            "node": "Alert me",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {},
  "tags": []
}
