{
  "name": "Handwritten Notes → Obsidian Vault",
  "nodes": [
    {
      "parameters": {
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "triggerOn": "specificFolder",
        "folderToWatch": {
          "__rl": true,
          "value": "",
          "mode": "list"
        },
        "event": "fileCreated",
        "options": {}
      },
      "name": "Notability PDF Added",
      "type": "n8n-nodes-base.googleDriveTrigger",
      "typeVersion": 1,
      "position": [
        -992,
        80
      ],
      "id": "df3a1d89-3056-4393-ae4b-5f114237f17b"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "1",
              "name": "model",
              "value": "claude-opus-4-8",
              "type": "string"
            },
            {
              "id": "2",
              "name": "systemPrompt",
              "value": "You are a handwriting transcription engine. You receive a PDF of handwritten notes (e.g. exported from Notability) and return a single JSON object — nothing else, no prose, no markdown fences around the whole thing.\n\n## Rules\n\n1. Transcribe VERBATIM. Do not summarize, rephrase, or \"improve\" the writing. Fix only obvious mechanical slips (a dropped letter in an otherwise clear word).\n2. Preserve structure: headings, numbered lists, bullet lists, indentation. Map them to GitHub-flavored markdown.\n3. For any word you cannot read with confidence, transcribe your best guess and wrap it in [square brackets with a trailing ?], e.g. [400?]. Never silently invent text to fill a gap — if a word is fully illegible write [illegible].\n4. Note crossed-out / struck text only if legible, in ~~strikethrough~~; otherwise omit.\n5. Do NOT add commentary, footnotes, or \"notes from the transcriber\" inside the markdown body. Observations go in metadata.notes_to_user.\n\n## Output schema\n\nReturn exactly this JSON object:\n\n{\n  \"title\": \"short title derived from the note's top heading or main topic\",\n  \"doc_type\": \"one of: book_notes | lecture | meeting | journal | todo | idea | other\",\n  \"source_work\": \"if the notes are about a specific book/paper/talk, its title; else null\",\n  \"markdown\": \"the full transcription as GFM markdown, including a top-level # heading\",\n  \"tags\": [\"lowercase\", \"kebab-case\", \"topical tags, 2-6 of them\"],\n  \"key_points\": [\"each distinct claim or takeaway as one plain-text bullet\"],\n  \"action_items\": [\"any explicit tasks/todos found, else empty array\"],\n  \"uncertain_terms\": [\"every word you bracketed, listed here for review\"],\n  \"notes_to_user\": \"1-2 sentences on anything ambiguous, or empty string\"\n}\n\nOutput the JSON object and nothing else.",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "name": "Set Config",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -768,
        80
      ],
      "id": "47be5b6f-01d6-45be-8b73-8fe708c85f81"
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Notability PDF Added').item.json.id }}"
        },
        "options": {}
      },
      "name": "Download PDF",
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        -544,
        80
      ],
      "id": "2f1db09b-7a9f-4eeb-adba-40d69660c946"
    },
    {
      "parameters": {
        "jsCode": "// Convert each incoming PDF's binary to base64.\n  // Uses getBinaryDataBuffer so it works whether n8n keeps binary in memory\n  // or on the filesystem (filesystem mode leaves item.binary.data.data empty).\n  const items = $input.all();\n  const out = [];\n  for (let i = 0; i < items.length; i++) {\n    const buffer = await this.helpers.getBinaryDataBuffer(i, 'data');\n    out.push({ json: { pdfBase64: buffer.toString('base64') } });\n  }\n  return out;"
      },
      "name": "To Base64",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -320,
        80
      ],
      "id": "17203403-52d1-4136-93f0-aed24c333c20"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            },
            {
              "name": "content-type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={ \"model\": \"{{ $('Set Config').item.json.model }}\", \"max_tokens\": 16000, \"system\": {{ JSON.stringify($('Set Config').item.json.systemPrompt) }}, \"messages\": [ { \"role\": \"user\", \"content\": [ { \"type\": \"document\", \"source\": { \"type\": \"base64\", \"media_type\": \"application/pdf\", \"data\": \"{{ $json.pdfBase64 }}\" } }, { \"type\": \"text\", \"text\": \"Transcribe these notes per your instructions and return only the JSON object.\" } ] } ] }",
        "options": {}
      },
      "name": "Anthropic Transcribe",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -112,
        80
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000,
      "id": "c06a2f17-1eb9-4083-bfd2-5584f88f3adc",
      "notes": "Set an HTTP Header Auth credential for x-api-key instead of inlining the key."
    },
    {
      "parameters": {
        "jsCode": "const resp = $input.first().json;\nconst text = (resp.content || []).map(b => b.type === 'text' ? b.text : '').join('');\nlet data;\ntry { data = JSON.parse(text); }\ncatch (e) { data = JSON.parse(text.replace(/```json|```/g, '').trim()); }\n\nconst driveFile = $('Notability PDF Added').first().json;\nconst arr = a => Array.isArray(a) ? a : [];\nconst fm = `---\\ntitle: \"${(data.title||'Untitled').replace(/\"/g,'\\\\\"')}\"\\nsource: \"${data.source_work||''}\"\\ntype: ${data.doc_type||'other'}\\ntags: [${arr(data.tags).join(', ')}]\\nimported: ${new Date().toISOString()}\\n---\\n\\n`;\n\nreturn [{ json: {\n  title: data.title || 'Untitled',\n  doc_type: data.doc_type || 'other',\n  source_work: data.source_work || null,\n  markdown: data.markdown || '',\n  tags: arr(data.tags),\n  key_points: arr(data.key_points),\n  action_items: arr(data.action_items),\n  uncertain_terms: arr(data.uncertain_terms),\n  notes_to_user: data.notes_to_user || '',\n  source_file: driveFile.name,\n  source_drive_id: driveFile.id,\n  filename: (data.title || 'note').replace(/[^a-z0-9]+/gi, '-').replace(/^-|-$/g, '').toLowerCase() + '.md',\n  vaultDoc: fm + (data.markdown || '')\n}}];"
      },
      "name": "Parse Output",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        128,
        80
      ],
      "id": "16a7f4c5-0dcc-4d86-99bd-7a896413a04a"
    },
    {
      "parameters": {
        "operation": "toText",
        "sourceProperty": "vaultDoc",
        "options": {
          "fileName": "={{ $json.filename }}"
        }
      },
      "name": "Markdown to File",
      "type": "n8n-nodes-base.convertToFile",
      "typeVersion": 1.1,
      "position": [
        336,
        -48
      ],
      "id": "2c38ec8c-2ec9-4010-a57f-4a1f419ec9b4"
    },
    {
      "parameters": {
        "name": "={{ $('Parse Output').item.json.filename }}",
        "driveId": {
          "__rl": true,
          "value": "My Drive",
          "mode": "list",
          "cachedResultName": "My Drive",
          "cachedResultUrl": "https://drive.google.com/drive/my-drive"
        },
        "folderId": {
          "__rl": true,
          "value": "",
          "mode": "list"
        },
        "options": {}
      },
      "name": "Write MD to Vault",
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        560,
        -48
      ],
      "id": "44e51e01-1454-4137-aa9b-d58a71c7ac0f"
    }
  ],
  "connections": {
    "Notability PDF Added": {
      "main": [
        [
          {
            "node": "Set Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Config": {
      "main": [
        [
          {
            "node": "Download PDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download PDF": {
      "main": [
        [
          {
            "node": "To Base64",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "To Base64": {
      "main": [
        [
          {
            "node": "Anthropic Transcribe",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Anthropic Transcribe": {
      "main": [
        [
          {
            "node": "Parse Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Output": {
      "main": [
        [
          {
            "node": "Markdown to File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Markdown to File": {
      "main": [
        [
          {
            "node": "Write MD to Vault",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate"
  }
}
