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 →
{
"name": "AI Technical Analysis \u2192 Iterative Preview (Generate + Critique + Refine Loop)",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "preview-iterative",
"responseMode": "responseNode",
"options": {}
},
"id": "i1000000-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": "action",
"name": "action",
"value": "={{ $json.body.action || 'generate' }}",
"type": "string"
},
{
"id": "previous-analysis",
"name": "previousAnalysis",
"value": "={{ $json.body.previousAnalysis ? JSON.stringify($json.body.previousAnalysis) : '' }}",
"type": "string"
},
{
"id": "feedback",
"name": "feedback",
"value": "={{ $json.body.feedback || '' }}",
"type": "string"
},
{
"id": "iteration",
"name": "iteration",
"value": "={{ $json.body.iteration || 0 }}",
"type": "number"
}
]
}
},
"id": "i1000000-0000-0000-0000-000000000002",
"name": "Set Variables",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
460,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "check-action",
"leftValue": "={{ $json.action }}",
"rightValue": "refine",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
}
},
"id": "i1000000-0000-0000-0000-000000000003",
"name": "Route by Action",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
680,
300
]
},
{
"parameters": {
"jsCode": "const featureDescription = $('Set Variables').first().json.featureDescription || '';\nconst additionalContext = $('Set Variables').first().json.additionalContext || '';\nconst template = $('Set Variables').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};\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 '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 '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 '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\nconst customRole = $('Set Variables').first().json.customRole || '';\nconst customSchema = $('Set Variables').first().json.customSchema || '';\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. No markdown code fences, no explanation \u2014 just the JSON object.\\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, systemRole: role, schema } }];"
},
"id": "i1000000-0000-0000-0000-000000000004",
"name": "Build Generate Request",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
900,
500
]
},
{
"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": "i1000000-0000-0000-0000-000000000005",
"name": "Call API - Generate",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1120,
500
]
},
{
"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 initial AI response: ' + e.message + '\\n\\nRaw: ' + content.substring(0, 500)); }\n\n// Pass through context from Build Generate Request\nconst gen = $('Build Generate Request').first().json;\nreturn [{ json: { analysis, featureDescription: gen.featureDescription, additionalContext: gen.additionalContext, systemRole: gen.systemRole, schema: gen.schema, authHeader: gen.authHeader } }];"
},
"id": "i1000000-0000-0000-0000-000000000006",
"name": "Parse Initial Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1340,
500
]
},
{
"parameters": {
"jsCode": "const prev = $input.first().json;\nconst model = $env.AI_MODEL || 'openai/gpt-4.1';\nconst maxTokens = parseInt($env.AI_MAX_TOKENS || '4096', 10);\n\nconst critiquePrompt = 'You previously produced this technical analysis:\\n\\n' + JSON.stringify(prev.analysis, null, 2) + '\\n\\nCritically review your own output. Identify:\\n1. Missing edge cases or security concerns\\n2. Overly vague or generic sections that need concrete details\\n3. Unrealistic estimates or missing tasks\\n4. Inconsistencies between sections\\n5. Anything a senior tech lead would push back on\\n\\nRespond ONLY with valid JSON:\\n{\\n \"strengths\": [\"what is good about this analysis\"],\\n \"weaknesses\": [\"what is missing, vague, or wrong\"],\\n \"suggestions\": [\"specific improvements to make\"]\\n}';\n\nreturn [{ json: { requestBody: { model, max_tokens: maxTokens, messages: [{ role: 'system', content: prev.systemRole }, { role: 'user', content: critiquePrompt }] }, authHeader: prev.authHeader, analysis: prev.analysis, featureDescription: prev.featureDescription, additionalContext: prev.additionalContext, systemRole: prev.systemRole, schema: prev.schema } }];"
},
"id": "i1000000-0000-0000-0000-000000000007",
"name": "Build Critique Request",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1560,
500
]
},
{
"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": "i1000000-0000-0000-0000-000000000008",
"name": "Call API - Critique",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1780,
500
]
},
{
"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 critique;\ntry { critique = JSON.parse(jsonStr); }\ncatch (e) { critique = { strengths: [], weaknesses: [content.substring(0, 500)], suggestions: ['Could not parse critique \u2014 using raw text as feedback'] }; }\n\nconst prev = $('Build Critique Request').first().json;\nconst model = $env.AI_MODEL || 'openai/gpt-4.1';\nconst maxTokens = parseInt($env.AI_MAX_TOKENS || '4096', 10);\n\nconst refinePrompt = 'Original feature description:\\n' + prev.featureDescription + '\\n\\nAdditional context:\\n' + prev.additionalContext + '\\n\\nYour initial analysis:\\n' + JSON.stringify(prev.analysis, null, 2) + '\\n\\nSelf-critique findings:\\n' + JSON.stringify(critique, null, 2) + '\\n\\nNow produce an IMPROVED version of the analysis that addresses all weaknesses and incorporates all suggestions. The improved version must be more specific, more detailed, and more actionable than the original.\\n\\n' + prev.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\\nRespond ONLY with valid JSON. No markdown code fences, no explanation \u2014 just the JSON object.';\n\nreturn [{ json: { requestBody: { model, max_tokens: maxTokens, messages: [{ role: 'system', content: prev.systemRole }, { role: 'user', content: refinePrompt }] }, authHeader: prev.authHeader, iteration: 1 } }];"
},
"id": "i1000000-0000-0000-0000-000000000009",
"name": "Build Auto-Refine Request",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2000,
500
]
},
{
"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": "i1000000-0000-0000-0000-000000000010",
"name": "Call API - Auto Refine",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2220,
500
]
},
{
"parameters": {
"jsCode": "const vars = $('Set Variables').first().json;\nconst template = vars.template || 'generic';\nconst previousAnalysis = vars.previousAnalysis ? JSON.parse(vars.previousAnalysis) : {};\nconst feedback = vars.feedback || '';\nconst iteration = (vars.iteration || 0) + 1;\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.',\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. 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};\n\nconst SCHEMAS = {\n 'scheduled-task-migration': 'Produce JSON with: title, summary, discoveryDocument (purpose with what/why/when, codeLocation, howItWorks, dataAccess, errorHandling, inputsAndOutputs, configuration, knownIssues, runInstructions), migrationPlan (targetDesign, dependencyMapping, phases, improvements, cleanupPhase, risks, openQuestions), estimatedComplexity, suggestedApproach.',\n 'adr': 'Produce JSON with: title, status, date, context, options, decision, consequences, followUp.',\n 'post-mortem': 'Produce JSON with: title, severity, duration, status, summary, impact, timeline, rootCause, detection, response, actionItems, lessonsLearned.',\n 'runbook': 'Produce JSON with: title, service, overview, healthChecks, commonIssues, procedures, contacts, links.',\n 'service-documentation': 'Produce JSON with: title, summary, overview, keyFiles, architecture, howToRun, directoryStructure, potentialIssues, improvements, dependencies, testing.',\n 'bug-fix': 'Produce JSON with: title, severity, description, reproductionSteps, expectedBehavior, actualBehavior, rootCause, fixApproach, tasks, testPlan, workaround.',\n 'dependency-update': 'Produce JSON with: title, packages, riskAssessment, tasks, verificationPlan, rollbackPlan.',\n 'tech-debt': 'Produce JSON with: title, currentState, desiredState, justification, approach, acceptanceCriteria, risks.',\n 'quick-enhancement': 'Produce JSON with: title, description, scope, implementation, acceptanceCriteria, testPlan.',\n 'api-breaking-change': 'Produce JSON with: title, summary, currentContract, proposedContract, diff, migrationPlan, communication, tasks, testing, rollbackPlan, risks.',\n 'security-audit': 'Produce JSON with: title, auditScope, overallRisk, findingsCount, findings, positiveFindings, recommendations, tasks, complianceNotes, retestDate.',\n 'performance-optimization': 'Produce JSON with: title, currentState, analysis, optimizations, quickWins, benchmarkPlan, tasks, monitoringPlan, antiPatterns.',\n 'tech-migration': 'Produce JSON with: title, currentState, targetState, impactAnalysis, migrationStrategy, phases, rollbackPlan, testing, risks, timeline.'\n};\n\nconst DEFAULT_SCHEMA = 'Produce JSON with: title, summary, architecture, apiContracts, databaseChanges, edgeCases, securityConsiderations, testingStrategy, tasks, estimatedComplexity, suggestedApproach.';\n\nconst customRole = vars.customRole || '';\nconst customSchema = vars.customSchema || '';\nconst role = customRole || ROLES[template] || ROLES['generic'];\nconst schema = customSchema || SCHEMAS[template] || DEFAULT_SCHEMA;\n\nconst refinePrompt = 'Here is the current technical analysis:\\n\\n' + JSON.stringify(previousAnalysis, null, 2) + '\\n\\nThe reviewer provided this feedback:\\n\\n' + feedback + '\\n\\nProduce an improved version of the analysis that addresses ALL of the reviewer feedback. Keep everything that was already good, and improve or add what was requested.\\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\\nRespond ONLY with valid JSON. No markdown code fences, no explanation \u2014 just the JSON object.';\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: 'system', content: role }, { role: 'user', content: refinePrompt }] }, authHeader, iteration } }];"
},
"id": "i1000000-0000-0000-0000-000000000011",
"name": "Build Feedback-Refine Request",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
900,
100
]
},
{
"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": "i1000000-0000-0000-0000-000000000012",
"name": "Call API - Feedback Refine",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1120,
100
]
},
{
"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\n// Determine iteration: generate branch = 1 (from auto-refine), refine branch = incremented\nconst action = $('Set Variables').first().json.action;\nlet iteration;\nif (action === 'refine') {\n iteration = ($('Set Variables').first().json.iteration || 0) + 1;\n} else {\n iteration = 1;\n}\n\nreturn [{ json: { analysis, iteration, featureDescription: $('Set Variables').first().json.featureDescription } }];"
},
"id": "i1000000-0000-0000-0000-000000000013",
"name": "Parse Final Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2440,
300
]
},
{
"parameters": {
"jsCode": "const { analysis, iteration } = $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) \u2014 Iterative Preview (iteration ' + iteration + ')\\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\nfunction renderSection(obj, depth) {\n if (!obj || typeof obj !== 'object') return String(obj || '') + '\\n';\n let out = '';\n if (Array.isArray(obj)) {\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 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, iteration } }];"
},
"id": "i1000000-0000-0000-0000-000000000014",
"name": "Format as Markdown",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2660,
300
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify($json) }}"
},
"id": "i1000000-0000-0000-0000-000000000015",
"name": "Send Response",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
2880,
300
]
}
],
"connections": {
"Webhook Trigger": {
"main": [
[
{
"node": "Set Variables",
"type": "main",
"index": 0
}
]
]
},
"Set Variables": {
"main": [
[
{
"node": "Route by Action",
"type": "main",
"index": 0
}
]
]
},
"Route by Action": {
"main": [
[
{
"node": "Build Feedback-Refine Request",
"type": "main",
"index": 0
}
],
[
{
"node": "Build Generate Request",
"type": "main",
"index": 0
}
]
]
},
"Build Generate Request": {
"main": [
[
{
"node": "Call API - Generate",
"type": "main",
"index": 0
}
]
]
},
"Call API - Generate": {
"main": [
[
{
"node": "Parse Initial Response",
"type": "main",
"index": 0
}
]
]
},
"Parse Initial Response": {
"main": [
[
{
"node": "Build Critique Request",
"type": "main",
"index": 0
}
]
]
},
"Build Critique Request": {
"main": [
[
{
"node": "Call API - Critique",
"type": "main",
"index": 0
}
]
]
},
"Call API - Critique": {
"main": [
[
{
"node": "Build Auto-Refine Request",
"type": "main",
"index": 0
}
]
]
},
"Build Auto-Refine Request": {
"main": [
[
{
"node": "Call API - Auto Refine",
"type": "main",
"index": 0
}
]
]
},
"Call API - Auto Refine": {
"main": [
[
{
"node": "Parse Final Response",
"type": "main",
"index": 0
}
]
]
},
"Build Feedback-Refine Request": {
"main": [
[
{
"node": "Call API - Feedback Refine",
"type": "main",
"index": 0
}
]
]
},
"Call API - Feedback Refine": {
"main": [
[
{
"node": "Parse Final Response",
"type": "main",
"index": 0
}
]
]
},
"Parse Final 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": "iterative"
}
]
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
AI Technical Analysis → Iterative Preview (Generate + Critique + Refine Loop). Uses httpRequest. Webhook trigger; 15 nodes.
Source: https://github.com/openmindednewby/ai-confluence-pipeline/blob/master/workflows/iterative-preview-pipeline.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
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
This flow creates dummy files for every item added in your *Arrs (Radarr/Sonarr) with the tag .
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
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
Sign PDF documents with legally-compliant digital signatures using X.509 certificates. Supports multiple PAdES signature levels (B, T, LT, LTA) with optional visible stamps.