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 Confluence \u2192 Jira (GitHub Models - Free)",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "analyze",
"responseMode": "responseNode",
"options": {}
},
"id": "webhook-trigger",
"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": "analysis-type",
"name": "analysisType",
"value": "={{ $json.body.analysisType || 'technical-analysis' }}",
"type": "string"
},
{
"id": "additional-context",
"name": "additionalContext",
"value": "={{ $json.body.additionalContext || '' }}",
"type": "string"
},
{
"id": "create-jira",
"name": "createJiraTasks",
"value": "={{ $json.body.createJiraTasks !== false }}",
"type": "boolean"
},
{
"id": "confluence-parent",
"name": "confluenceParentPageId",
"value": "={{ $json.body.confluenceParentPageId || '' }}",
"type": "string"
}
]
}
},
"id": "set-variables",
"name": "Set Variables",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
460,
300
]
},
{
"parameters": {
"jsCode": "// Build the API request body safely using JSON.stringify\n// This properly escapes backslashes, quotes, newlines, etc. in user input\nconst featureDescription = $input.first().json.featureDescription || '';\nconst additionalContext = $input.first().json.additionalContext || '';\n\nconst prompt = `You are a senior software architect performing technical analysis for a development team.\n\nGiven the following feature description, produce a detailed technical analysis as a JSON object.\n\n## Feature Description\n${featureDescription}\n\n## Additional Context\n${additionalContext}\n\n## Output Format\n\nRespond ONLY with valid JSON matching this schema:\n\n{\n \"title\": \"Short descriptive title\",\n \"summary\": \"2-3 sentence executive summary\",\n \"architecture\": {\n \"overview\": \"High-level architecture description\",\n \"components\": [{\"name\": \"...\", \"type\": \"frontend|backend|database|infrastructure\", \"description\": \"...\", \"changes\": \"...\"}],\n \"dataFlow\": \"Data flow description\"\n },\n \"apiContracts\": [{\"method\": \"GET|POST|PUT|DELETE\", \"path\": \"/api/...\", \"description\": \"...\", \"requestBody\": {}, \"responseBody\": {}, \"statusCodes\": [\"200 - OK\"]}],\n \"databaseChanges\": [{\"type\": \"new-table|alter-table\", \"entity\": \"...\", \"description\": \"...\", \"fields\": [{\"name\": \"...\", \"type\": \"...\", \"nullable\": false}]}],\n \"edgeCases\": [{\"scenario\": \"...\", \"impact\": \"low|medium|high\", \"mitigation\": \"...\"}],\n \"securityConsiderations\": [\"...\"],\n \"testingStrategy\": {\"unitTests\": [\"...\"], \"integrationTests\": [\"...\"], \"e2eTests\": [\"...\"]},\n \"tasks\": [{\"type\": \"epic|story|subtask\", \"summary\": \"...\", \"description\": \"...\", \"component\": \"frontend|backend|database|devops|testing\", \"estimate\": \"XS|S|M|L|XL\", \"priority\": \"Critical|High|Medium|Low\", \"acceptanceCriteria\": [\"Given X, when Y, then Z\"]}],\n \"estimatedComplexity\": \"low|medium|high\",\n \"suggestedApproach\": \"Recommended implementation order\"\n}\n\nRules: Tasks should be 1-3 day work items. Include Gherkin acceptance criteria. Be specific, not generic.`;\n\nconst model = $env.AI_MODEL || 'openai/gpt-4.1';\nconst maxTokens = parseInt($env.AI_MAX_TOKENS || '4096', 10);\n\nconst requestBody = {\n model,\n max_tokens: maxTokens,\n messages: [{ role: 'user', content: prompt }]\n};\n\nconst authHeader = 'Bearer ' + ($env.GITHUB_TOKEN || '');\n\nreturn [{ json: { requestBody, authHeader } }];"
},
"id": "build-request",
"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) }}"
},
"id": "call-github-models",
"name": "Call GitHub Models API",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
900,
300
]
},
{
"parameters": {
"jsCode": "// Extract JSON from GitHub Models (OpenAI-compatible) response\nconst response = $input.first().json;\nconst content = response.choices[0].message.content;\n\n// Parse the JSON (handle markdown code fences if present)\nlet jsonStr = content;\nif (content.includes('```json')) {\n jsonStr = content.split('```json')[1].split('```')[0].trim();\n} else if (content.includes('```')) {\n jsonStr = content.split('```')[1].split('```')[0].trim();\n}\n\nlet analysis;\ntry {\n analysis = JSON.parse(jsonStr);\n} catch (e) {\n throw new Error(`Failed to parse AI response as JSON: ${e.message}\\n\\nRaw response: ${content.substring(0, 500)}`);\n}\n\n// Get variables from earlier node\nconst vars = $('Set Variables').first().json;\n\nreturn [{\n json: {\n analysis,\n featureDescription: vars.featureDescription,\n createJiraTasks: vars.createJiraTasks,\n confluenceParentPageId: vars.confluenceParentPageId\n }\n}];"
},
"id": "parse-response",
"name": "Parse AI Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1120,
300
]
},
{
"parameters": {
"jsCode": "// Convert analysis JSON to Confluence-friendly HTML\nconst { analysis } = $input.first().json;\n\nlet html = '';\nhtml += `<h2>Summary</h2><p>${analysis.summary}</p>`;\nhtml += `<h2>Architecture</h2><p>${analysis.architecture.overview}</p>`;\nhtml += `<h3>Components</h3><table><thead><tr><th>Component</th><th>Type</th><th>Description</th><th>Changes</th></tr></thead><tbody>`;\nfor (const c of analysis.architecture.components || []) {\n html += `<tr><td><strong>${c.name}</strong></td><td><code>${c.type}</code></td><td>${c.description}</td><td>${c.changes}</td></tr>`;\n}\nhtml += `</tbody></table>`;\nif (analysis.architecture.dataFlow) html += `<h3>Data Flow</h3><p>${analysis.architecture.dataFlow}</p>`;\nif (analysis.apiContracts?.length) {\n html += `<h2>API Contracts</h2>`;\n for (const api of analysis.apiContracts) {\n html += `<h3><code>${api.method} ${api.path}</code></h3><p>${api.description}</p>`;\n if (api.statusCodes?.length) html += `<p><strong>Status Codes:</strong> ${api.statusCodes.join(', ')}</p>`;\n }\n}\nif (analysis.databaseChanges?.length) {\n html += `<h2>Database Changes</h2><table><thead><tr><th>Type</th><th>Entity</th><th>Description</th></tr></thead><tbody>`;\n for (const db of analysis.databaseChanges) html += `<tr><td><code>${db.type}</code></td><td><strong>${db.entity}</strong></td><td>${db.description}</td></tr>`;\n html += `</tbody></table>`;\n}\nif (analysis.edgeCases?.length) {\n html += `<h2>Edge Cases</h2><table><thead><tr><th>Scenario</th><th>Impact</th><th>Mitigation</th></tr></thead><tbody>`;\n for (const ec of analysis.edgeCases) html += `<tr><td>${ec.scenario}</td><td><code>${ec.impact}</code></td><td>${ec.mitigation}</td></tr>`;\n html += `</tbody></table>`;\n}\nif (analysis.securityConsiderations?.length) {\n html += `<h2>Security</h2><ul>`;\n for (const s of analysis.securityConsiderations) html += `<li>${s}</li>`;\n html += `</ul>`;\n}\nif (analysis.tasks?.length) {\n html += `<h2>Task Breakdown</h2><table><thead><tr><th>Type</th><th>Summary</th><th>Component</th><th>Estimate</th><th>Priority</th></tr></thead><tbody>`;\n for (const t of analysis.tasks) html += `<tr><td><code>${t.type}</code></td><td>${t.summary}</td><td><code>${t.component}</code></td><td>${t.estimate}</td><td>${t.priority}</td></tr>`;\n html += `</tbody></table>`;\n}\nhtml += `<h2>Overall</h2><p><strong>Complexity:</strong> ${analysis.estimatedComplexity}</p><p><strong>Approach:</strong> ${analysis.suggestedApproach}</p>`;\nhtml += `<hr/><p><em>Generated by <a href=\"https://github.com/openmindednewby/ai-confluence-pipeline\">ai-confluence-pipeline</a> on ${new Date().toISOString().split('T')[0]}</em></p>`;\n\nreturn [{ json: { html, title: analysis.title, analysis: $input.first().json.analysis, createJiraTasks: $input.first().json.createJiraTasks, confluenceParentPageId: $input.first().json.confluenceParentPageId } }];"
},
"id": "format-confluence",
"name": "Format for Confluence",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1340,
300
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.CONFLUENCE_BASE_URL }}/wiki/rest/api/content",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"type\": \"page\",\n \"title\": \"{{ $json.title }} - Technical Analysis\",\n \"space\": { \"key\": \"{{ $env.CONFLUENCE_SPACE_KEY }}\" },\n {{ $json.confluenceParentPageId ? '\"ancestors\": [{\"id\": \"' + $json.confluenceParentPageId + '\"}],' : '' }}\n \"body\": {\n \"storage\": {\n \"value\": {{ JSON.stringify($json.html) }},\n \"representation\": \"storage\"\n }\n },\n \"metadata\": {\n \"labels\": [\n { \"prefix\": \"global\", \"name\": \"technical-analysis\" },\n { \"prefix\": \"global\", \"name\": \"n8n-pipeline-generated\" }\n ]\n }\n}"
},
"id": "create-confluence-page",
"name": "Create Confluence Page",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1560,
300
],
"credentials": {
"httpBasicAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "check-jira",
"leftValue": "={{ $('Parse AI Response').first().json.createJiraTasks }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
}
},
"id": "check-create-jira",
"name": "Create Jira Tasks?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1780,
300
]
},
{
"parameters": {
"jsCode": "const analysis = $('Parse AI Response').first().json.analysis;\nconst confluencePage = $('Create Confluence Page').first().json;\nconst confluenceUrl = confluencePage._links?.base + confluencePage._links?.webui;\nconst tasks = analysis.tasks || [];\nconst estimateToPoints = { 'XS': 1, 'S': 2, 'M': 3, 'L': 5, 'XL': 8 };\nreturn tasks.map(task => ({ json: { task, storyPoints: estimateToPoints[task.estimate] || 3, confluenceUrl, pageTitle: analysis.title } }));"
},
"id": "prepare-jira-tasks",
"name": "Prepare Jira Tasks",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2000,
200
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.JIRA_BASE_URL }}/rest/api/3/issue",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"fields\": {\n \"project\": { \"key\": \"{{ $env.JIRA_PROJECT_KEY }}\" },\n \"summary\": {{ JSON.stringify($json.task.summary) }},\n \"description\": {\n \"type\": \"doc\",\n \"version\": 1,\n \"content\": [\n { \"type\": \"paragraph\", \"content\": [{ \"type\": \"text\", \"text\": {{ JSON.stringify($json.task.description) }} }] },\n { \"type\": \"paragraph\", \"content\": [{ \"type\": \"text\", \"text\": \"Technical Analysis: \" }, { \"type\": \"text\", \"text\": {{ JSON.stringify($json.pageTitle) }}, \"marks\": [{ \"type\": \"link\", \"attrs\": { \"href\": {{ JSON.stringify($json.confluenceUrl || '') }} } }] }] }\n ]\n },\n \"issuetype\": { \"name\": \"{{ $json.task.type === 'epic' ? ($env.JIRA_EPIC_ISSUE_TYPE || 'Epic') : $json.task.type === 'subtask' ? ($env.JIRA_SUBTASK_ISSUE_TYPE || 'Sub-task') : ($env.JIRA_STORY_ISSUE_TYPE || 'Story') }}\" },\n \"priority\": { \"name\": \"{{ $json.task.priority || $env.JIRA_DEFAULT_PRIORITY || 'Medium' }}\" },\n \"labels\": [\"n8n-pipeline-generated\", \"{{ $json.task.component }}\"]\n }\n}"
},
"id": "create-jira-issue",
"name": "Create Jira Issue",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2220,
200
],
"credentials": {
"httpBasicAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const confluencePage = $('Create Confluence Page').first().json;\nconst analysis = $('Parse AI Response').first().json.analysis;\nconst jiraIssues = $input.all().map(item => item.json);\nreturn [{ json: { success: true, confluencePage: { id: confluencePage.id, title: confluencePage.title, url: (confluencePage._links?.base || '') + (confluencePage._links?.webui || '') }, jiraIssues: jiraIssues.map(issue => ({ key: issue.key, summary: issue.fields?.summary, url: `${process.env.JIRA_BASE_URL}/browse/${issue.key}` })), taskCount: jiraIssues.length, complexity: analysis.estimatedComplexity } }];"
},
"id": "aggregate-results",
"name": "Aggregate Results",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2440,
200
]
},
{
"parameters": {
"jsCode": "const confluencePage = $('Create Confluence Page').first().json;\nconst analysis = $('Parse AI Response').first().json.analysis;\nreturn [{ json: { success: true, confluencePage: { id: confluencePage.id, title: confluencePage.title, url: (confluencePage._links?.base || '') + (confluencePage._links?.webui || '') }, jiraIssues: [], taskCount: 0, complexity: analysis.estimatedComplexity, note: 'Jira task creation was skipped (createJiraTasks=false)' } }];"
},
"id": "skip-jira-result",
"name": "Confluence Only Result",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2000,
420
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ $json }}"
},
"id": "respond-webhook",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
2660,
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 for Confluence",
"type": "main",
"index": 0
}
]
]
},
"Format for Confluence": {
"main": [
[
{
"node": "Create Confluence Page",
"type": "main",
"index": 0
}
]
]
},
"Create Confluence Page": {
"main": [
[
{
"node": "Create Jira Tasks?",
"type": "main",
"index": 0
}
]
]
},
"Create Jira Tasks?": {
"main": [
[
{
"node": "Prepare Jira Tasks",
"type": "main",
"index": 0
}
],
[
{
"node": "Confluence Only Result",
"type": "main",
"index": 0
}
]
]
},
"Prepare Jira Tasks": {
"main": [
[
{
"node": "Create Jira Issue",
"type": "main",
"index": 0
}
]
]
},
"Create Jira Issue": {
"main": [
[
{
"node": "Aggregate Results",
"type": "main",
"index": 0
}
]
]
},
"Aggregate Results": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Confluence Only Result": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"tags": [
{
"name": "ai-pipeline"
},
{
"name": "technical-analysis"
},
{
"name": "github-models"
},
{
"name": "free"
}
]
}
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.
httpBasicAuth
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
AI Technical Analysis → Confluence → Jira (GitHub Models - Free). Uses httpRequest. Webhook trigger; 13 nodes.
Source: https://github.com/openmindednewby/ai-confluence-pipeline/blob/master/workflows/github-models-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 .
eek-Go v2 (Batch-Then-Review). Uses httpRequest. Webhook trigger; 75 nodes.
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