AutomationFlowsWeb Scraping › AI Technical Analysis → Preview (markdown)

AI Technical Analysis → Preview (markdown)

AI Technical Analysis → Preview (Markdown). Uses httpRequest. Webhook trigger; 7 nodes.

Webhook trigger★★★★☆ complexity7 nodesHTTP Request
Web Scraping Trigger: Webhook Nodes: 7 Complexity: ★★★★☆ Added:

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": "AI Technical Analysis \u2192 Preview (Markdown)",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "preview",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "a1000000-0000-0000-0000-000000000001",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "feature-desc",
              "name": "featureDescription",
              "value": "={{ $json.body.featureDescription }}",
              "type": "string"
            },
            {
              "id": "additional-context",
              "name": "additionalContext",
              "value": "={{ $json.body.additionalContext || '' }}",
              "type": "string"
            },
            {
              "id": "template-id",
              "name": "template",
              "value": "={{ $json.body.template || 'generic' }}",
              "type": "string"
            },
            {
              "id": "custom-role",
              "name": "customRole",
              "value": "={{ $json.body.customRole || '' }}",
              "type": "string"
            },
            {
              "id": "custom-schema",
              "name": "customSchema",
              "value": "={{ $json.body.customSchema || '' }}",
              "type": "string"
            }
          ]
        }
      },
      "id": "a1000000-0000-0000-0000-000000000002",
      "name": "Set Variables",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        460,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "const featureDescription = $input.first().json.featureDescription || '';\nconst additionalContext = $input.first().json.additionalContext || '';\nconst template = $input.first().json.template || 'generic';\n\nconst ROLES = {\n  'generic': 'You are a senior software architect performing technical analysis.',\n  'new-feature': 'You are a senior software architect designing a new feature.',\n  'tech-migration': 'You are a senior architect planning a technology migration. Must be incremental and reversible.',\n  'large-refactoring': 'You are a senior architect planning a major refactoring. Must preserve existing behavior.',\n  'api-breaking-change': 'You are a senior API architect planning a breaking change. Minimize consumer disruption.',\n  'security-audit': 'You are a senior security engineer documenting audit findings with severity scores and fixes.',\n  'performance-optimization': 'You are a senior performance engineer with measurable improvement targets.',\n  'scheduled-task-migration': 'You are a senior architect migrating a legacy scheduled task to a modern job framework. Produce a Discovery Document and Migration Plan.',\n  'adr': 'You are a senior architect documenting an Architecture Decision Record.',\n  'post-mortem': 'You are a senior SRE writing a blameless post-mortem.',\n  'runbook': 'You are a senior SRE writing a runbook. Every command must be copy-pasteable.',\n  'service-documentation': 'You are a senior software engineer writing internal documentation for a service, application, or library. Your audience is developers new to this codebase who need to get up to speed quickly. Be specific and practical.',\n  'bug-fix': 'You are a senior developer triaging a bug with root cause analysis.',\n  'dependency-update': 'You are a senior developer planning a dependency upgrade.',\n  'tech-debt': 'You are a senior developer documenting tech debt with business justification.',\n  'quick-enhancement': 'You are a senior developer scoping a small enhancement (< 1 day).',\n  'legacy-technical': 'You are a senior software architect performing technical analysis.',\n  'legacy-bug': 'You are a senior engineer performing root cause analysis on a bug.',\n  'legacy-spike': 'You are a senior architect evaluating technical options.'\n};\n\nconst SCHEMAS = {\n  'scheduled-task-migration': 'Produce JSON with: title, summary, discoveryDocument (purpose with what/why/when, codeLocation with workerClass/baseClass/entryPoint/projectFile/supportingFiles each with path, howItWorks with entryFlow and coreAlgorithm steps each with codeSample and sourceFile and lineRange, dataAccess with databases and externalServices, errorHandling with strategy and codeSample, inputsAndOutputs with inputs/outputs/sideEffects, configuration, knownIssues, runInstructions with prerequisites/buildSteps/runSteps/debugSteps/testSteps), migrationPlan (targetDesign with projectName/className/jobId/interface/targetPath/namespace, dependencyMapping with mappings each having legacy/legacyFile/target/action, phases each with name/goal/prerequisite/canRollback/rollbackSteps/attentionPoints/tasks/validationChecks, improvements with codeQuality/linting/testing/performance/observability, cleanupPhase with filesToRemove and configToRemove, risks, openQuestions), estimatedComplexity, suggestedApproach. Every code reference MUST include file path.',\n  'adr': 'Produce JSON with: title, status (Proposed), date, context (background, constraints, drivers, assumptions), options (each with name, description, pros, cons, effort, risk, operationalImpact, teamFamiliarity), decision (chosen, reasoning, dissent), consequences (positive, negative, neutral), followUp (actions, reviewDate, reversibility).',\n  'post-mortem': 'Produce JSON with: title, severity (SEV1-4), duration, status, summary, impact (usersAffected, revenueImpact, dataLoss, slaBreached), timeline (timestamp, event, actor), rootCause (primary, contributing, fiveWhys), detection (howDetected, timeToDetect, alertsFired, alertsExpectedButMissing), response (timeToMitigate, mitigationSteps, whatWorkedWell, whatCouldBeImproved), actionItems (description, type: prevent|detect|mitigate, priority, owner, deadline), lessonsLearned.',\n  'runbook': 'Produce JSON with: title, service, overview (purpose, criticality, dependencies, dependents), healthChecks (name, command, healthyOutput, unhealthyOutput), commonIssues (symptom, cause, diagnosis steps, resolution steps, escalation), procedures (name, when, steps with instruction/expectedResult/ifFailed, rollback), contacts, links.',\n  'bug-fix': 'Produce JSON with: title, severity, description, reproductionSteps, expectedBehavior, actualBehavior, rootCause (hypothesis, confidence, investigation), fixApproach (description, affectedFiles, riskLevel), tasks as subtasks with acceptanceCriteria, testPlan (unitTests, manualVerification), workaround.',\n  'dependency-update': 'Produce JSON with: title, packages (name, currentVersion, targetVersion, changelog, breakingChanges with description/affectedCode/migration, newFeatures, deprecations), riskAssessment (overall, peerDependencies, knownIssues), tasks as subtasks, verificationPlan, rollbackPlan.',\n  'tech-debt': 'Produce JSON with: title, currentState (description, pain, frequency), desiredState (description, benefit), justification (developerProductivity, reliability, riskReduction, onboarding), approach (description, canBeIncremental, estimatedEffort, bestTimeToFix), acceptanceCriteria, risks.',\n  'quick-enhancement': 'Produce JSON with: title, description, scope (includes, excludes, isActuallyBigger, biggerNote), implementation (approach, affectedFiles, estimate max M), acceptanceCriteria (max 5), testPlan.',\n  'api-breaking-change': 'Produce JSON with: title, summary, currentContract (endpoints, consumers with impactLevel), proposedContract (endpoints with changeType, versioningStrategy), diff (field, before, after, breakingReason, migrationAction), migrationPlan (strategy, phases, deprecationTimeline, migrationGuide with steps and codeExamples), communication (announcement, channels, faq), tasks, testing (contractTests, migrationTests, compatibilityTests), rollbackPlan, risks.',\n  'security-audit': 'Produce JSON with: title, auditScope (areasReviewed, areasOutOfScope, methodology), overallRisk, findingsCount by severity, findings (id like SEC-001, title, severity, category, owaspCategory, description, affectedComponent, reproductionSteps, impact, exploitability, evidence, remediation with recommendation/codeExample/effort/priority), positiveFindings, recommendations (immediate, shortTerm, longTerm), tasks, complianceNotes, retestDate.',\n  'performance-optimization': 'Produce JSON with: title, currentState (metrics with name/currentValue/target/gap, userImpact, businessImpact), analysis (bottlenecks with location/type/description/evidence/contribution%, hotPaths, redHerrings), optimizations (id like OPT-001, title, description, type, targetBottleneck, expectedImprovement, confidence, effort, risk, tradeoff), quickWins, benchmarkPlan (tooling, baselineTests, regressionTests, loadProfile), tasks, monitoringPlan (dashboards, alerts, continuousBaseline), antiPatterns.',\n  'service-documentation': 'Produce JSON with: title, summary, overview (purpose, type: service|application|library|cli-tool|worker|scheduled-job, techStack, repository, owners), keyFiles (path, purpose, notes), architecture (overview, entryPoint, keyModules with name/path/responsibility/publicInterface, dataFlow), howToRun (prerequisites, setup steps, run with development/production/docker commands, environment with variable/description/required/default, verification), directoryStructure (description, tree with path/description), potentialIssues (issue, severity: low|medium|high, context, workaround), improvements (title, description, effort: XS|S|M|L|XL, impact: low|medium|high, category: code-quality|performance|reliability|developer-experience|security|testing), dependencies (runtime, external, consumers), testing (howToTest, testStructure, coverage).',\n  'tech-migration': 'Produce JSON with: title, currentState (technology, version, usage, knownIssues), targetState (technology, version, benefits, tradeoffs), impactAnalysis (affectedServices with impactLevel, affectedTeams, breakingChanges, dataChanges), migrationStrategy (approach: strangler-fig|parallel-run|feature-flag, reasoning, parallelRunPeriod, featureFlags), phases (name, goal, prerequisite, canRollback, rollbackSteps, tasks, validationChecks), rollbackPlan (fullRollbackSteps, pointOfNoReturn, dataRollback), testing (parallelRunTests, regressionTests, newTests, performanceBenchmarks), risks with contingency, timeline.'\n};\n\nconst DEFAULT_SCHEMA = 'Produce JSON with: title, summary, architecture (overview, components with name/type/description/changes, dataFlow), apiContracts (method, path, description, requestBody, responseBody, statusCodes), databaseChanges (type, entity, description, fields with name/type/nullable), edgeCases (scenario, impact, mitigation), securityConsiderations, testingStrategy (unitTests, integrationTests, e2eTests), tasks (type: epic|story|subtask, summary, description, component, estimate: XS|S|M|L|XL, priority, acceptanceCriteria in Given/When/Then), estimatedComplexity, suggestedApproach.';\n\n// Custom prompts: if customRole/customSchema are provided, use them directly\nconst customRole = $input.first().json.customRole || '';\nconst customSchema = $input.first().json.customSchema || '';\n\nconst role = customRole || ROLES[template] || ROLES['generic'];\nconst schema = customSchema || SCHEMAS[template] || DEFAULT_SCHEMA;\n\nconst prompt = role + '\\n\\nAnalyze the following and produce a detailed JSON response.\\n\\n## Description\\n' + featureDescription + '\\n\\n## Additional Context\\n' + additionalContext + '\\n\\n## Output\\n\\nRespond ONLY with valid JSON.\\n\\n' + schema + '\\n\\nAlso include: title, summary, estimatedComplexity (low|medium|high), suggestedApproach.\\nRules: Tasks 1-3 day items. Gherkin acceptance criteria. Be specific. XS(<2h) S(2-4h) M(4-8h) L(1-2d) XL(2-3d).';\n\nconst model = $env.AI_MODEL || 'openai/gpt-4.1';\nconst maxTokens = parseInt($env.AI_MAX_TOKENS || '4096', 10);\nconst authHeader = 'Bearer ' + ($env.GITHUB_TOKEN || '');\n\nreturn [{ json: { requestBody: { model, max_tokens: maxTokens, messages: [{ role: 'user', content: prompt }] }, authHeader, featureDescription, additionalContext, template } }];"
      },
      "id": "a1000000-0000-0000-0000-000000000003",
      "name": "Build API Request",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        680,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://models.github.ai/inference/chat/completions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ $json.authHeader }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Accept",
              "value": "application/vnd.github+json"
            },
            {
              "name": "X-GitHub-Api-Version",
              "value": "2026-03-10"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json.requestBody) }}",
        "options": {
          "timeout": 120000
        }
      },
      "id": "a1000000-0000-0000-0000-000000000004",
      "name": "Call GitHub Models API",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        900,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "const response = $input.first().json;\nconst content = response.choices[0].message.content;\n\nlet jsonStr = content;\nif (content.includes('```json')) jsonStr = content.split('```json')[1].split('```')[0].trim();\nelse if (content.includes('```')) jsonStr = content.split('```')[1].split('```')[0].trim();\n\nlet analysis;\ntry { analysis = JSON.parse(jsonStr); }\ncatch (e) { throw new Error('Failed to parse AI response: ' + e.message + '\\n\\nRaw: ' + content.substring(0, 500)); }\n\nreturn [{ json: { analysis, featureDescription: $('Set Variables').first().json.featureDescription } }];"
      },
      "id": "a1000000-0000-0000-0000-000000000005",
      "name": "Parse AI Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1120,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "const { analysis } = $input.first().json;\nconst date = new Date().toISOString().split('T')[0];\nlet md = '';\n\nmd += '# ' + (analysis.title || 'Analysis') + '\\n\\n';\nmd += '> Generated on ' + date + ' by [ai-confluence-pipeline](https://github.com/openmindednewby/ai-confluence-pipeline)\\n\\n';\nif (analysis.estimatedComplexity) md += '**Complexity:** ' + analysis.estimatedComplexity;\nif (analysis.suggestedApproach) md += ' | **Approach:** ' + analysis.suggestedApproach;\nmd += '\\n\\n---\\n\\n';\nif (analysis.summary) md += '## Summary\\n\\n' + analysis.summary + '\\n\\n';\n\n// Generic renderer: recursively convert JSON to markdown\nfunction renderSection(obj, depth) {\n  if (!obj || typeof obj !== 'object') return String(obj || '') + '\\n';\n  let out = '';\n  if (Array.isArray(obj)) {\n    // Check if array of objects with consistent keys (table candidate)\n    if (obj.length > 0 && typeof obj[0] === 'object' && !Array.isArray(obj[0])) {\n      const keys = Object.keys(obj[0]);\n      if (keys.length <= 8 && keys.length >= 2 && obj.every(item => typeof item === 'object' && !Array.isArray(item))) {\n        out += '| ' + keys.map(k => k.replace(/([A-Z])/g, ' $1').trim()).join(' | ') + ' |\\n';\n        out += '| ' + keys.map(() => '---').join(' | ') + ' |\\n';\n        for (const item of obj) {\n          out += '| ' + keys.map(k => {\n            const v = item[k];\n            if (Array.isArray(v)) return v.join(', ');\n            if (typeof v === 'object' && v !== null) return JSON.stringify(v);\n            return String(v ?? '');\n          }).join(' | ') + ' |\\n';\n        }\n        out += '\\n';\n        return out;\n      }\n    }\n    for (const item of obj) {\n      if (typeof item === 'string') out += '- ' + item + '\\n';\n      else if (typeof item === 'object') out += renderSection(item, depth);\n    }\n    out += '\\n';\n    return out;\n  }\n  // Object\n  const skip = ['title', 'summary', 'estimatedComplexity', 'suggestedApproach'];\n  for (const [key, value] of Object.entries(obj)) {\n    if (skip.includes(key) && depth === 0) continue;\n    const heading = key.replace(/([A-Z])/g, ' $1').replace(/^./, s => s.toUpperCase()).trim();\n    if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n      out += '**' + heading + ':** ' + value + '\\n\\n';\n    } else if (Array.isArray(value) && value.length > 0 && typeof value[0] === 'string') {\n      out += '**' + heading + ':**\\n';\n      for (const item of value) out += '- ' + item + '\\n';\n      out += '\\n';\n    } else if (value && typeof value === 'object') {\n      const hPrefix = '#'.repeat(Math.min(depth + 2, 4));\n      out += hPrefix + ' ' + heading + '\\n\\n';\n      out += renderSection(value, depth + 1);\n    }\n  }\n  return out;\n}\n\nmd += renderSection(analysis, 0);\n\nreturn [{ json: { success: true, title: analysis.title || 'Analysis', markdown: md, analysis } }];"
      },
      "id": "a1000000-0000-0000-0000-000000000006",
      "name": "Format as Markdown",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1340,
        300
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}"
      },
      "id": "a1000000-0000-0000-0000-000000000007",
      "name": "Send Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1560,
        300
      ]
    }
  ],
  "connections": {
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Set Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Variables": {
      "main": [
        [
          {
            "node": "Build API Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build API Request": {
      "main": [
        [
          {
            "node": "Call GitHub Models API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call GitHub Models API": {
      "main": [
        [
          {
            "node": "Parse AI Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse AI Response": {
      "main": [
        [
          {
            "node": "Format as Markdown",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format as Markdown": {
      "main": [
        [
          {
            "node": "Send Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "tags": [
    {
      "name": "ai-pipeline"
    },
    {
      "name": "preview"
    },
    {
      "name": "github-models"
    }
  ]
}
Pro

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

About this workflow

AI Technical Analysis → Preview (Markdown). Uses httpRequest. Webhook trigger; 7 nodes.

Source: https://github.com/openmindednewby/ai-confluence-pipeline/blob/master/workflows/preview-pipeline.json — original creator credit. Request a take-down →

More Web Scraping workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Web Scraping

This n8n template provides enterprise-level version control for your workflows using GitHub integration. Stop losing hours to broken workflows and manual exports – get proper commit history, visual di

n8n, Execute Workflow Trigger, HTTP Request +1
Web Scraping

This flow creates dummy files for every item added in your *Arrs (Radarr/Sonarr) with the tag .

HTTP Request, Ssh
Web Scraping

eek-Go v2 (Batch-Then-Review). Uses httpRequest. Webhook trigger; 75 nodes.

HTTP Request
Web Scraping

This workflow receives webhook requests from a content calendar and uses the X API v2 to publish text posts, threads, image/video posts, and polls, as well as delete existing posts and run a credentia

HTTP Request
Web Scraping

This workflow acts as a central API gateway for all technical indicator agents in the Binance Spot Market Quant AI system. It listens for incoming webhook requests and dynamically routes them to the c

HTTP Request