AutomationFlowsWeb Scraping › Aidp - Main Workflow

Aidp - Main Workflow

AIDP - Main Workflow. Uses executeCommand, httpRequest, jira. Webhook trigger; 12 nodes.

Webhook trigger★★★★☆ complexity12 nodesExecute CommandHTTP RequestJira
Web Scraping Trigger: Webhook Nodes: 12 Complexity: ★★★★☆ Added:

This workflow follows the Executecommand → HTTP Request recipe pattern — see all workflows that pair these two integrations.

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": "AIDP - Main Workflow",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "aidp-trigger",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "webhook-trigger",
      "name": "Jira Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1.1,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "check-label",
              "leftValue": "={{ $json.issue.fields.labels }}",
              "rightValue": "ai-task",
              "operator": {
                "type": "array",
                "operation": "contains"
              }
            },
            {
              "id": "check-status",
              "leftValue": "={{ $json.issue.fields.status.name }}",
              "rightValue": "In Progress",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "filter-conditions",
      "name": "Filter AI Tasks",
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2,
      "position": [
        460,
        300
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Extract and validate required fields from Jira issue\nconst issue = $input.item.json.issue;\nconst fields = issue.fields;\n\n// Required fields\nconst jiraKey = issue.key;\nconst projectKey = jiraKey.split('-')[0];\nconst summary = fields.summary;\n\n// Handle Atlassian Document Format (ADF) description\nlet descriptionText = '';\nif (typeof fields.description === 'string') {\n  descriptionText = fields.description;\n} else if (fields.description?.content) {\n  // Parse ADF to plain text\n  const extractText = (node) => {\n    if (!node) return '';\n    if (node.type === 'text') return node.text || '';\n    if (node.content) return node.content.map(extractText).join('');\n    return '';\n  };\n  descriptionText = fields.description.content.map(extractText).join('\\n');\n}\n\n// Knowledge base: Project -> Default Repo mapping\nconst REPO_MAPPING = {\n  'SCRUM': 'https://github.com/andresKillem/aidp-test-repo',\n  'DEFAULT': 'https://github.com/andresKillem'\n};\n\n// Smart repo URL resolution:\n// 1. Try custom field\n// 2. Try extracting from description\n// 3. Use project mapping\nlet repoUrl = fields.customfield_10039;\n\nif (!repoUrl) {\n  // Try to extract GitHub URL from description\n  const githubMatch = descriptionText.match(/https:\\/\\/github\\.com\\/[\\w-]+\\/[\\w.-]+/);\n  if (githubMatch) {\n    repoUrl = githubMatch[0].replace(/\\.git$/, '');\n  }\n}\n\nif (!repoUrl) {\n  // Use project mapping\n  repoUrl = REPO_MAPPING[projectKey] || REPO_MAPPING['DEFAULT'];\n}\n\nconst baseBranch = fields.customfield_10040 || 'main';\n\n// Parse acceptance criteria from description\nlet acceptanceCriteria = '';\nconst acMatch = descriptionText.match(/(?:acceptance criteria|ac)[:\\s]*([\\s\\S]*?)(?=##|$)/i);\nif (acMatch) {\n  acceptanceCriteria = acMatch[1].trim();\n}\n\n// Generate branch name\nconst slugify = (text) => text\n  .toLowerCase()\n  .replace(/[^a-z0-9]+/g, '-')\n  .replace(/^-+|-+$/g, '')\n  .substring(0, 50);\n\nconst branchName = `ai/${jiraKey.toLowerCase()}-${slugify(summary)}`;\n\nreturn {\n  jiraKey,\n  projectKey,\n  jiraUrl: `https://polarpipeline.atlassian.net/browse/${jiraKey}`,\n  summary,\n  description: descriptionText,\n  acceptanceCriteria,\n  repoUrl,\n  baseBranch,\n  branchName,\n  priority: fields.priority?.name || 'Medium',\n  reporter: fields.reporter?.displayName || 'Unknown',\n  timestamp: new Date().toISOString()\n};"
      },
      "id": "parse-issue",
      "name": "Parse Issue Data",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        680,
        300
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Build the prompt from template\nconst data = $input.item.json;\n\nconst promptTemplate = `# Task: ${data.summary}\n\n## Context\n\n- **Repository**: ${data.repoUrl}\n- **Base Branch**: ${data.baseBranch}\n- **Jira Issue**: [${data.jiraKey}](${data.jiraUrl})\n- **Feature Branch**: ${data.branchName}\n\n## Requirements\n\n${data.description}\n\n## Acceptance Criteria\n\n${data.acceptanceCriteria || 'Not specified - use best judgment based on requirements.'}\n\n## Instructions\n\nFollow these steps in order:\n\n1. **Explore First**: Read the codebase to understand existing patterns, architecture, and conventions.\n2. **Plan Before Coding**: Think through the implementation approach.\n3. **Implement Incrementally**: Make changes in logical, atomic steps with tests.\n4. **Commit with Context**: Use conventional commit format with Jira key.\n5. **Self-Review**: Verify all acceptance criteria are addressed.\n\n## Constraints\n\n- DO NOT modify files unrelated to this task\n- DO NOT create a Pull Request - only commit and push\n- DO keep changes minimal and focused\n- DO follow existing patterns exactly\n\n## Output Format\n\nWhen complete, provide a summary of changes made, tests added, and acceptance criteria status.`;\n\nreturn {\n  ...data,\n  prompt: promptTemplate\n};"
      },
      "id": "build-prompt",
      "name": "Build Prompt",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        900,
        300
      ]
    },
    {
      "parameters": {
        "command": "={{ 'docker exec aidp-claude-executor /usr/local/bin/aidp-executor \"' + $json.repoUrl + '\" \"' + $json.branchName + '\" /dev/stdin \"' + $json.jiraKey + '\" \"' + $json.baseBranch + '\" <<EOF\\n' + $json.prompt + '\\nEOF' }}"
      },
      "id": "execute-claude",
      "name": "Execute Claude Code",
      "type": "n8n-nodes-base.executeCommand",
      "typeVersion": 1,
      "position": [
        1120,
        300
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Parse executor result\nconst stdout = $input.item.json.stdout || '';\nlet result;\n\ntry {\n  // Find JSON in output (last valid JSON object)\n  const jsonMatch = stdout.match(/\\{[\\s\\S]*\\}(?=[^}]*$)/);\n  if (jsonMatch) {\n    result = JSON.parse(jsonMatch[0]);\n  } else {\n    throw new Error('No JSON found in output');\n  }\n} catch (e) {\n  result = {\n    status: 'error',\n    error_message: `Failed to parse executor output: ${e.message}`,\n    raw_output: stdout.substring(0, 2000)\n  };\n}\n\nreturn {\n  ...$input.item.json,\n  executorResult: result,\n  success: result.status === 'success'\n};"
      },
      "id": "parse-result",
      "name": "Parse Result",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1340,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "check-success",
              "leftValue": "={{ $json.success }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "check-success",
      "name": "Success?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1560,
        300
      ]
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "requestMethod": "POST",
        "url": "=https://api.github.com/repos/{{ $json.repoUrl.replace('https://github.com/', '').replace('.git', '') }}/pulls",
        "jsonParameters": true,
        "options": {},
        "bodyParametersJson": "={{ JSON.stringify({\n  title: `[${$json.jiraKey}] ${$json.summary}`,\n  head: $json.branchName,\n  base: $json.baseBranch,\n  body: `## Summary\\n\\n${$json.summary}\\n\\n## Jira Issue\\n\\n[${$json.jiraKey}](${$json.jiraUrl})\\n\\n## Changes Made\\n\\n${$json.executorResult.claude_summary || 'See commits for details'}\\n\\n## Acceptance Criteria\\n\\n${$json.acceptanceCriteria}\\n\\n---\\n\ud83e\udd16 *This PR was generated by AIDP (AI-Powered Development Pipeline)*`,\n  draft: false\n}) }}"
      },
      "id": "create-pr",
      "name": "Create PR",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        1780,
        200
      ],
      "credentials": {
        "oAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "requestMethod": "POST",
        "url": "=https://api.github.com/repos/{{ $json.repoUrl.replace('https://github.com/', '').replace('.git', '') }}/issues/{{ $json.prNumber }}/labels",
        "jsonParameters": true,
        "options": {},
        "bodyParametersJson": "={{ JSON.stringify({ labels: ['ai-generated', 'needs-review'] }) }}"
      },
      "id": "add-labels",
      "name": "Add PR Labels",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        2000,
        200
      ],
      "credentials": {
        "oAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "issue",
        "operation": "comment",
        "issueKey": "={{ $json.jiraKey }}",
        "comment": "=\u2705 **AIDP Completed Successfully**\\n\\n\ud83d\udd17 **Pull Request**: [PR #{{ $json.prNumber }}]({{ $json.prUrl }})\\n\\n**Branch**: `{{ $json.branchName }}`\\n\\n**Commits**: {{ $json.executorResult.commit_count || 0 }}\\n\\n---\\n_Awaiting human review before merge._"
      },
      "id": "jira-comment-success",
      "name": "Jira Comment (Success)",
      "type": "n8n-nodes-base.jira",
      "typeVersion": 1,
      "position": [
        2220,
        200
      ],
      "credentials": {
        "jiraSoftwareCloudApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "issue",
        "operation": "comment",
        "issueKey": "={{ $json.jiraKey }}",
        "comment": "=\u274c **AIDP Failed**\\n\\n**Error**: {{ $json.executorResult.error_message || 'Unknown error' }}\\n\\n**Status**: {{ $json.executorResult.status }}\\n\\n---\\n_Please review the task requirements and try again, or assign to a human developer._"
      },
      "id": "jira-comment-error",
      "name": "Jira Comment (Error)",
      "type": "n8n-nodes-base.jira",
      "typeVersion": 1,
      "position": [
        1780,
        400
      ],
      "credentials": {
        "jiraSoftwareCloudApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ status: 'processed', jiraKey: $json.jiraKey }) }}"
      },
      "id": "respond-webhook",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        2440,
        300
      ]
    }
  ],
  "connections": {
    "Jira Webhook": {
      "main": [
        [
          {
            "node": "Filter AI Tasks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter AI Tasks": {
      "main": [
        [
          {
            "node": "Parse Issue Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Issue Data": {
      "main": [
        [
          {
            "node": "Build Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Prompt": {
      "main": [
        [
          {
            "node": "Execute Claude Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute Claude Code": {
      "main": [
        [
          {
            "node": "Parse Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Result": {
      "main": [
        [
          {
            "node": "Success?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Success?": {
      "main": [
        [
          {
            "node": "Create PR",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Jira Comment (Error)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create PR": {
      "main": [
        [
          {
            "node": "Add PR Labels",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add PR Labels": {
      "main": [
        [
          {
            "node": "Jira Comment (Success)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Jira Comment (Success)": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Jira Comment (Error)": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner"
  },
  "staticData": null,
  "tags": [
    {
      "name": "AIDP",
      "id": "1"
    }
  ]
}

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.

Pro

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

About this workflow

AIDP - Main Workflow. Uses executeCommand, httpRequest, jira. Webhook trigger; 12 nodes.

Source: https://github.com/andresKillem/aidp/blob/8839fb212f6336a3aa9793485da729542e0fd7da/n8n-workflows/main-workflow.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

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.

Execute Command, HTTP Request, Read Write File +1
Web Scraping

MLOps Pipeline EN-PT. Uses executeCommand, httpRequest, errorTrigger. Webhook trigger; 18 nodes.

Execute Command, HTTP Request, Error Trigger
Web Scraping

AI Product Video Generator (Windows). Uses httpRequest, writeBinaryFile, executeCommand, readBinaryFile. Webhook trigger; 16 nodes.

HTTP Request, Write Binary File, Execute Command +1
Web Scraping

MLOps Pipeline - Hand Talk. Uses executeCommand, httpRequest. Webhook trigger; 15 nodes.

Execute Command, HTTP Request
Web Scraping

AIDP - Main Workflow v2. Uses executeCommand, httpRequest. Webhook trigger; 13 nodes.

Execute Command, HTTP Request