{
  "id": "pjvStandupStat01",
  "name": "Standup & Status Agent",
  "nodes": [
    {
      "parameters": {
        "content": "## Standup & Status Agent\nRuns every weekday at 09:00. Pulls project updates, asks GPT to write the standup/status summary, detects blockers, posts a digest and escalates blockers.\n\n**Configure:** the tracker URL, your OpenAI key in the 'Summarise' node header, and the Slack webhook URLs.",
        "height": 260,
        "width": 340
      },
      "id": "note1",
      "name": "About",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [200, 40]
    },
    {
      "parameters": {
        "rule": { "interval": [ { "field": "cronExpression", "expression": "0 9 * * 1-5" } ] }
      },
      "id": "sched1",
      "name": "Every weekday 09:00",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [240, 360]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "https://your-tracker.example.com/rest/api/2/search?jql=updated>=-1d",
        "authentication": "none",
        "options": {}
      },
      "id": "http1",
      "name": "Get Project Updates",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [480, 360]
    },
    {
      "parameters": {
        "jsCode": "// Shape the raw tracker payload into a compact context for the LLM.\nconst issues = ($input.first().json.issues || []).map(i => ({\n  key: i.key,\n  summary: i.fields?.summary,\n  status: i.fields?.status?.name,\n  assignee: i.fields?.assignee?.displayName || 'Unassigned',\n  due: i.fields?.duedate || null\n}));\nconst prompt = `Write a concise daily standup summary and flag anything blocked or overdue. Return JSON: {\"summary\": string, \"blockers\": string[]}.\\n\\nIssues:\\n${JSON.stringify(issues, null, 2)}`;\nreturn [{ json: { prompt } }];"
      },
      "id": "code1",
      "name": "Build Prompt",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [720, 360]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/chat/completions",
        "sendHeaders": true,
        "headerParameters": { "parameters": [ { "name": "Authorization", "value": "Bearer YOUR_OPENAI_API_KEY" }, { "name": "Content-Type", "value": "application/json" } ] },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"model\": \"gpt-4o-mini\",\n  \"messages\": [\n    { \"role\": \"system\", \"content\": \"You are a project standup assistant. Reply ONLY with valid JSON.\" },\n    { \"role\": \"user\", \"content\": {{ JSON.stringify($json.prompt) }} }\n  ],\n  \"temperature\": 0.3\n}",
        "options": {}
      },
      "id": "http2",
      "name": "Summarise (GPT)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [960, 360]
    },
    {
      "parameters": {
        "jsCode": "// Parse the model output and count blockers.\nlet parsed = { summary: '', blockers: [] };\ntry { parsed = JSON.parse($json.choices[0].message.content); } catch (e) {}\nreturn [{ json: { summary: parsed.summary || '', blockers: parsed.blockers || [], blockerCount: (parsed.blockers || []).length } }];"
      },
      "id": "code2",
      "name": "Parse & Detect Blockers",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [1200, 360]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://hooks.slack.com/services/YOUR/DAILY/WEBHOOK",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"text\": {{ JSON.stringify(\"*Daily standup*\\n\" + $json.summary) }}\n}",
        "options": {}
      },
      "id": "http3",
      "name": "Post Daily Digest",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1440, 360]
    },
    {
      "parameters": {
        "conditions": {
          "options": { "caseSensitive": true, "typeValidation": "loose" },
          "combinator": "and",
          "conditions": [ { "leftValue": "={{ $json.blockerCount }}", "rightValue": 0, "operator": { "type": "number", "operation": "gt" } } ]
        },
        "options": {}
      },
      "id": "if1",
      "name": "Any blockers?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [1680, 360]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://hooks.slack.com/services/YOUR/ESCALATION/WEBHOOK",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"text\": {{ JSON.stringify(\":rotating_light: Blockers need attention:\\n- \" + ($json.blockers || []).join(\"\\n- \")) }}\n}",
        "options": {}
      },
      "id": "http4",
      "name": "Escalate Blockers",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1920, 260]
    }
  ],
  "connections": {
    "Every weekday 09:00": { "main": [ [ { "node": "Get Project Updates", "type": "main", "index": 0 } ] ] },
    "Get Project Updates": { "main": [ [ { "node": "Build Prompt", "type": "main", "index": 0 } ] ] },
    "Build Prompt": { "main": [ [ { "node": "Summarise (GPT)", "type": "main", "index": 0 } ] ] },
    "Summarise (GPT)": { "main": [ [ { "node": "Parse & Detect Blockers", "type": "main", "index": 0 } ] ] },
    "Parse & Detect Blockers": { "main": [ [ { "node": "Post Daily Digest", "type": "main", "index": 0 } ] ] },
    "Post Daily Digest": { "main": [ [ { "node": "Any blockers?", "type": "main", "index": 0 } ] ] },
    "Any blockers?": { "main": [ [ { "node": "Escalate Blockers", "type": "main", "index": 0 } ], [] ] }
  },
  "settings": { "executionOrder": "v1" },
  "active": false,
  "pinData": {},
  "meta": { "templateCredsSetupCompleted": false }
}
