This workflow follows the Agent → Anthropic Chat 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 →
{
"name": "[Strategy Drift] Strategy Command Center",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 2,14 * * *"
}
]
}
},
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
200,
500
],
"id": "cc-0001-0001-4000-a000-000000000001",
"name": "Every 12 Hours (Offset)"
},
{
"parameters": {
"resource": "databasePage",
"operation": "getAll",
"databaseId": {
"__rl": true,
"value": "d920771332d841eb80886086dff7d18f",
"mode": "id"
},
"returnAll": false,
"limit": 200,
"sort": {
"sortValue": [
{
"key": "created_time",
"direction": "descending"
}
]
}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
460,
200
],
"id": "cc-0001-0002-4000-a000-000000000002",
"name": "Fetch Strategy Signals",
"credentials": {
"notionApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"resource": "databasePage",
"operation": "getAll",
"databaseId": {
"__rl": true,
"value": "25d67380a5bf4cb1b53f9367bea1dbb2",
"mode": "id"
},
"returnAll": true
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
460,
400
],
"id": "cc-0001-0003-4000-a000-000000000003",
"name": "Fetch Assumptions",
"credentials": {
"notionApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"resource": "databasePage",
"operation": "getAll",
"databaseId": {
"__rl": true,
"value": "fa40e0a6543e461d807397dab158dafc",
"mode": "id"
},
"returnAll": true
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
460,
600
],
"id": "cc-0001-0004-4000-a000-000000000004",
"name": "Fetch Drift Alerts",
"credentials": {
"notionApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"resource": "databasePage",
"operation": "getAll",
"databaseId": {
"__rl": true,
"value": "f41cc42b27e44a249d98f451f964fa59",
"mode": "id"
},
"returnAll": false,
"limit": 50,
"sort": {
"sortValue": [
{
"key": "created_time",
"direction": "descending"
}
]
}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
460,
800
],
"id": "cc-0001-0005-4000-a000-000000000005",
"name": "Fetch Competitive Intel",
"credentials": {
"notionApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"resource": "databasePage",
"operation": "getAll",
"databaseId": {
"__rl": true,
"value": "e65e9f8fa8b24402b845c23adef807a7",
"mode": "id"
},
"returnAll": true
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
460,
1000
],
"id": "cc-0001-0006-4000-a000-000000000006",
"name": "Fetch Metrics",
"credentials": {
"notionApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "src-signals",
"name": "_source",
"value": "signals",
"type": "string"
}
]
},
"options": {
"includeBinary": false
}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
700,
200
],
"id": "cc-0001-0007-4000-a000-000000000007",
"name": "Tag: Signals"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "src-assumptions",
"name": "_source",
"value": "assumptions",
"type": "string"
}
]
},
"options": {
"includeBinary": false
}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
700,
400
],
"id": "cc-0001-0008-4000-a000-000000000008",
"name": "Tag: Assumptions"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "src-alerts",
"name": "_source",
"value": "alerts",
"type": "string"
}
]
},
"options": {
"includeBinary": false
}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
700,
600
],
"id": "cc-0001-0009-4000-a000-000000000009",
"name": "Tag: Alerts"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "src-competitive",
"name": "_source",
"value": "competitive",
"type": "string"
}
]
},
"options": {
"includeBinary": false
}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
700,
800
],
"id": "cc-0001-0010-4000-a000-000000000010",
"name": "Tag: Competitive"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "src-metrics",
"name": "_source",
"value": "metrics",
"type": "string"
}
]
},
"options": {
"includeBinary": false
}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
700,
1000
],
"id": "cc-0001-0011-4000-a000-000000000011",
"name": "Tag: Metrics"
},
{
"parameters": {
"mode": "append",
"options": {}
},
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
940,
300
],
"id": "cc-0001-0012-4000-a000-000000000012",
"name": "Merge Signals+Assumptions"
},
{
"parameters": {
"mode": "append",
"options": {}
},
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
940,
700
],
"id": "cc-0001-0013-4000-a000-000000000013",
"name": "Merge Alerts+Competitive"
},
{
"parameters": {
"mode": "append",
"options": {}
},
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
1180,
500
],
"id": "cc-0001-0014-4000-a000-000000000014",
"name": "Merge Top+Bottom"
},
{
"parameters": {
"mode": "append",
"options": {}
},
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
1180,
700
],
"id": "cc-0001-0015-4000-a000-000000000015",
"name": "Merge All Data"
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "const allItems = $input.all();\nconst now = new Date();\nconst nowStr = now.toISOString().replace('T', ' ').substring(0, 16) + ' UTC';\nconst dateStr = now.toISOString().split('T')[0];\n\n// Helper to extract Notion properties\nfunction getProp(item, propName) {\n const props = item.json.properties || item.json;\n const prop = props[propName];\n if (!prop) return null;\n if (prop.title) return prop.title.map(t => t.text?.content || t.plain_text || '').join('');\n if (prop.rich_text) return prop.rich_text.map(t => t.text?.content || t.plain_text || '').join('');\n if (prop.select) return prop.select?.name || '';\n if (prop.multi_select) return prop.multi_select.map(s => s.name).join(', ');\n if (prop.number !== undefined) return prop.number;\n if (prop.checkbox !== undefined) return prop.checkbox;\n if (prop.date) return prop.date?.start || '';\n if (prop.url) return prop.url || '';\n if (prop.status) return prop.status?.name || '';\n return String(prop);\n}\n\n// Separate by source\nconst signals = allItems.filter(i => i.json._source === 'signals');\nconst assumptions = allItems.filter(i => i.json._source === 'assumptions');\nconst alerts = allItems.filter(i => i.json._source === 'alerts');\nconst competitive = allItems.filter(i => i.json._source === 'competitive');\nconst metrics = allItems.filter(i => i.json._source === 'metrics');\n\n// ===== ASSUMPTION HEALTH =====\nconst assumptionRows = [];\nfor (const a of assumptions) {\n const code = getProp(a, 'Code') || getProp(a, 'Assumption Code') || getProp(a, 'Name') || '';\n const name = getProp(a, 'Name') || getProp(a, 'Title') || '';\n const confidence = getProp(a, 'Confidence') ?? 'N/A';\n const status = getProp(a, 'Status') || '?';\n const direction = getProp(a, 'Direction') || getProp(a, 'Trend') || '?';\n\n let indicator = '\\ud83d\\udfe2';\n const conf = parseInt(confidence);\n if (!isNaN(conf)) {\n if (conf < 40) indicator = '\\ud83d\\udd34';\n else if (conf < 60) indicator = '\\ud83d\\udfe1';\n }\n assumptionRows.push({ code, name, confidence, status, direction, indicator });\n}\n\n// ===== SIGNAL ANALYSIS =====\nconst sourceCounts = {};\nconst layerCounts = { L1: 0, L2: 0, L3: 0, L4: 0, L5: 0, Other: 0 };\nconst severityCounts = { Critical: 0, High: 0, Medium: 0, Low: 0 };\nconst recentSignals = [];\nconst last7days = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);\nconst last30days = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);\nlet signals7d = 0;\nlet signals30d = 0;\n\nfor (const s of signals) {\n const source = getProp(s, 'Source') || 'Unknown';\n sourceCounts[source] = (sourceCounts[source] || 0) + 1;\n\n const severity = getProp(s, 'Severity') || 'Low';\n severityCounts[severity] = (severityCounts[severity] || 0) + 1;\n\n const title = getProp(s, 'Name') || getProp(s, 'Title') || '';\n const summary = getProp(s, 'Summary') || '';\n const created = new Date(s.json.created_time || s.json.createdTime || '');\n\n // Layer detection from title prefix\n if (title.includes('[L1]') || title.toLowerCase().includes('agent runtime')) layerCounts.L1++;\n else if (title.includes('[L2]') || title.toLowerCase().includes('mcp') || title.toLowerCase().includes('skill')) layerCounts.L2++;\n else if (title.includes('[L3]') || title.toLowerCase().includes('memory')) layerCounts.L3++;\n else if (title.includes('[L4]') || title.toLowerCase().includes('observ') || title.toLowerCase().includes('token')) layerCounts.L4++;\n else if (title.includes('[L5]') || title.toLowerCase().includes('governance') || title.toLowerCase().includes('trust')) layerCounts.L5++;\n else layerCounts.Other++;\n\n if (created > last7days) signals7d++;\n if (created > last30days) signals30d++;\n\n if (created > last7days) {\n recentSignals.push({ title, severity, summary, source, date: created.toISOString().split('T')[0] });\n }\n}\n\n// ===== DRIFT ALERTS =====\nlet openAlerts = 0;\nlet criticalAlerts = 0;\nconst alertList = [];\nfor (const al of alerts) {\n const status = getProp(al, 'Status') || '';\n const severity = getProp(al, 'Severity') || '';\n const title = getProp(al, 'Name') || getProp(al, 'Title') || '';\n if (status !== 'Resolved' && status !== 'Closed') {\n openAlerts++;\n if (severity === 'Critical') criticalAlerts++;\n alertList.push({ title, severity, status });\n }\n}\n\n// ===== COMPETITIVE INTEL =====\nconst competitorMoves = [];\nfor (const c of competitive) {\n const company = getProp(c, 'Company') || getProp(c, 'Name') || getProp(c, 'Title') || '';\n const threat = getProp(c, 'Threat Level') || '';\n const summary = getProp(c, 'Summary') || getProp(c, 'Notes') || getProp(c, 'Key Move') || '';\n const created = new Date(c.json.created_time || c.json.createdTime || '');\n if (created > last30days) {\n competitorMoves.push({ company, threat, summary, date: created.toISOString().split('T')[0] });\n }\n}\n\n// ===== CALCULATE OVERALL HEALTH =====\nconst avgConfidence = assumptionRows.reduce((sum, a) => {\n const c = parseInt(a.confidence);\n return sum + (isNaN(c) ? 50 : c);\n}, 0) / Math.max(assumptionRows.length, 1);\n\nlet healthLabel = 'STABLE';\nif (avgConfidence < 40 || criticalAlerts > 2) healthLabel = 'CRITICAL';\nelse if (avgConfidence < 60 || criticalAlerts > 0 || openAlerts > 3) healthLabel = 'WEAKENING';\nconst healthScore = Math.round(avgConfidence);\n\n// ===== GENERATE CHART URLs =====\n// 1. Layer distribution radar chart\nconst radarConfig = {\n type: 'radar',\n data: {\n labels: ['Agent Runtime', 'Skill Network', 'Memory', 'Observability', 'Governance'],\n datasets: [{\n label: 'Issue Count',\n data: [layerCounts.L1, layerCounts.L2, layerCounts.L3, layerCounts.L4, layerCounts.L5],\n backgroundColor: 'rgba(54, 162, 235, 0.2)',\n borderColor: 'rgba(54, 162, 235, 1)',\n pointBackgroundColor: 'rgba(54, 162, 235, 1)'\n }]\n },\n options: { title: { display: true, text: 'Community Pain by Strategy Layer' }, scale: { ticks: { beginAtZero: true } } }\n};\nconst radarChartUrl = 'https://quickchart.io/chart?w=500&h=400&c=' + encodeURIComponent(JSON.stringify(radarConfig));\n\n// 2. Assumption confidence bar chart\nconst gaugeConfig = {\n type: 'bar',\n data: {\n labels: assumptionRows.map(a => a.code),\n datasets: [{\n label: 'Confidence',\n data: assumptionRows.map(a => parseInt(a.confidence) || 0),\n backgroundColor: assumptionRows.map(a => {\n const c = parseInt(a.confidence) || 0;\n if (c >= 60) return 'rgba(46, 204, 113, 0.8)';\n if (c >= 40) return 'rgba(241, 196, 15, 0.8)';\n return 'rgba(231, 76, 60, 0.8)';\n })\n }]\n },\n options: {\n title: { display: true, text: 'Assumption Confidence Levels' },\n scales: { yAxes: [{ ticks: { beginAtZero: true, max: 100 } }] },\n legend: { display: false }\n }\n};\nconst gaugeChartUrl = 'https://quickchart.io/chart?w=600&h=300&c=' + encodeURIComponent(JSON.stringify(gaugeConfig));\n\n// 3. Signal source pie chart\nconst sourceLabels = Object.keys(sourceCounts);\nconst sourceData = Object.values(sourceCounts);\nconst pieConfig = {\n type: 'doughnut',\n data: {\n labels: sourceLabels,\n datasets: [{\n data: sourceData,\n backgroundColor: ['#3498db', '#e74c3c', '#2ecc71', '#f39c12', '#9b59b6', '#1abc9c', '#e67e22', '#95a5a6']\n }]\n },\n options: { title: { display: true, text: 'Signal Sources' } }\n};\nconst pieChartUrl = 'https://quickchart.io/chart?w=400&h=300&c=' + encodeURIComponent(JSON.stringify(pieConfig));\n\n// 4. Severity distribution\nconst sevConfig = {\n type: 'horizontalBar',\n data: {\n labels: ['Critical', 'High', 'Medium', 'Low'],\n datasets: [{\n label: 'Signals',\n data: [severityCounts.Critical, severityCounts.High, severityCounts.Medium, severityCounts.Low],\n backgroundColor: ['#e74c3c', '#e67e22', '#f1c40f', '#95a5a6']\n }]\n },\n options: { title: { display: true, text: 'Signal Severity Distribution' }, legend: { display: false }, scales: { xAxes: [{ ticks: { beginAtZero: true } }] } }\n};\nconst sevChartUrl = 'https://quickchart.io/chart?w=500&h=250&c=' + encodeURIComponent(JSON.stringify(sevConfig));\n\n// ===== WAVE ROADMAP ALIGNMENT =====\nconst waveAlignment = [\n {\n wave: 'W1: Runtime',\n when: 'Wk 1-8',\n layers: 'L1, L2, L3',\n communityDemand: layerCounts.L1 + layerCounts.L2 + layerCounts.L3 > 20 ? '\\ud83d\\udd34 HIGH' : (layerCounts.L1 + layerCounts.L2 + layerCounts.L3 > 10 ? '\\ud83d\\udfe1 MEDIUM' : '\\ud83d\\udfe2 LOW'),\n issueCount: layerCounts.L1 + layerCounts.L2 + layerCounts.L3\n },\n {\n wave: 'W2: Workforce',\n when: 'Wk 5-14',\n layers: 'L2, L4',\n communityDemand: layerCounts.L2 + layerCounts.L4 > 15 ? '\\ud83d\\udd34 HIGH' : (layerCounts.L2 + layerCounts.L4 > 7 ? '\\ud83d\\udfe1 MEDIUM' : '\\ud83d\\udfe2 LOW'),\n issueCount: layerCounts.L2 + layerCounts.L4\n },\n {\n wave: 'W3: OS',\n when: 'Wk 11-24',\n layers: 'L4, L5',\n communityDemand: layerCounts.L4 + layerCounts.L5 > 10 ? '\\ud83d\\udd34 HIGH' : (layerCounts.L4 + layerCounts.L5 > 5 ? '\\ud83d\\udfe1 MEDIUM' : '\\ud83d\\udfe2 LOW'),\n issueCount: layerCounts.L4 + layerCounts.L5\n }\n];\n\nreturn [{\n json: {\n dateStr,\n nowStr,\n healthLabel,\n healthScore,\n assumptionRows,\n layerCounts,\n severityCounts,\n signals7d,\n signals30d,\n openAlerts,\n criticalAlerts,\n alertList,\n recentSignals: recentSignals.slice(0, 15),\n competitorMoves: competitorMoves.slice(0, 10),\n waveAlignment,\n radarChartUrl,\n gaugeChartUrl,\n pieChartUrl,\n sevChartUrl,\n sourceCounts,\n totalSignals: signals.length\n }\n}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1420,
600
],
"id": "cc-0001-0016-4000-a000-000000000016",
"name": "Build Dashboard Data"
},
{
"parameters": {
"text": "={{ JSON.stringify($json) }}",
"options": {
"systemMessage": "You are the chief strategy officer writing a brief, opinionated market-and-roadmap narrative.\n\nGiven the dashboard data, write TWO sections (each 3-5 paragraphs max):\n\nSECTION 1: MARKET SHIFTS\nWhat's changing in the AI agent/automation market RIGHT NOW? Use the competitive intelligence, signal sources, and assumption health to tell the story. Be specific \u2014 name companies, cite data points, identify inflection points. Connect each shift to our strategy layers (L1-L5) and assumptions (A1-A6). End with: what does this mean for our position?\n\nSECTION 2: ROADMAP IMPLICATIONS\nGiven community demand (issue counts by layer), assumption health, and market shifts:\n1. What should we ACCELERATE? (backed by data)\n2. What should we DE-PRIORITIZE? (backed by data)\n3. What NEW bets should we consider? (emerging patterns)\n4. What's the biggest risk if we don't adjust?\n\nBe direct. Use numbers. No fluff. Write for an exec who has 3 minutes.\nFormat as clean markdown with ## headers.",
"maxIterations": 10
}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 2,
"position": [
1660,
600
],
"id": "cc-0001-0017-4000-a000-000000000017",
"name": "AI Narrative"
},
{
"parameters": {
"model": {
"__rl": true,
"value": "claude-haiku-4-5-20251001",
"mode": "id"
},
"options": {
"maxTokensToSample": 4096,
"temperature": 0.4
}
},
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"typeVersion": 1.3,
"position": [
1660,
820
],
"id": "cc-0001-0018-4000-a000-000000000018",
"name": "Claude Haiku",
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "const narrative = $input.first().json.output || $input.first().json.text || '';\nconst d = $('Build Dashboard Data').first().json;\n\nlet page = '**Last updated:** ' + d.nowStr + '\\n\\n';\npage += '---\\n\\n';\n\n// HEALTH AT A GLANCE\npage += '## Strategy Health: ' + d.healthLabel + ' (' + d.healthScore + '/100)\\n\\n';\npage += '**Signals:** ' + d.totalSignals + ' total | ' + d.signals7d + ' this week | ' + d.signals30d + ' this month\\n';\npage += '**Drift Alerts:** ' + d.openAlerts + ' open (' + d.criticalAlerts + ' critical)\\n\\n';\n\n// LAYER HEALTH TABLE\npage += '## Community Pain by Strategy Layer\\n\\n';\npage += '\\n\\n';\nconst layerNames = { L1: 'Agent Runtime', L2: 'Skill Network', L3: 'Persistent Memory', L4: 'Agent Observability', L5: 'Trust & Governance' };\npage += '| Layer | Issues | Severity Distribution |\\n';\npage += '|-------|--------|----------------------|\\n';\nfor (const l of ['L1', 'L2', 'L3', 'L4', 'L5']) {\n const count = d.layerCounts[l] || 0;\n const pct = d.totalSignals > 0 ? Math.round((count / d.totalSignals) * 100) : 0;\n const bar = '\\u2588'.repeat(Math.min(Math.round(pct / 5), 20)) + ' ' + pct + '%';\n page += '| **' + l + ': ' + layerNames[l] + '** | ' + count + ' | ' + bar + ' |\\n';\n}\npage += '\\n';\n\n// ASSUMPTION HEALTH\npage += '## Assumption Confidence\\n\\n';\npage += '\\n\\n';\npage += '| Assumption | Confidence | Status | Direction |\\n';\npage += '|-----------|-----------|--------|----------|\\n';\nfor (const a of d.assumptionRows) {\n page += '| ' + a.indicator + ' ' + a.code + ': ' + a.name + ' | ' + a.confidence + '/100 | ' + a.status + ' | ' + a.direction + ' |\\n';\n}\npage += '\\n';\n\n// SIGNAL SEVERITY\npage += '## Signal Severity\\n\\n';\npage += '\\n\\n';\n\n// SIGNAL SOURCES\npage += '## Signal Sources\\n\\n';\npage += '\\n\\n';\n\n// RECENT SIGNALS\nif (d.recentSignals && d.recentSignals.length > 0) {\n page += '## Recent Signals (Last 7 Days)\\n\\n';\n for (const s of d.recentSignals) {\n const sevEmoji = s.severity === 'Critical' ? '\\ud83d\\udd34' : s.severity === 'High' ? '\\ud83d\\udfe0' : s.severity === 'Medium' ? '\\ud83d\\udfe1' : '\\u26aa';\n page += '- ' + sevEmoji + ' **' + s.title + '** (' + s.source + ', ' + s.date + ')\\n';\n if (s.summary) page += ' ' + s.summary + '\\n';\n }\n page += '\\n';\n}\n\n// COMPETITOR MOVES\nif (d.competitorMoves && d.competitorMoves.length > 0) {\n page += '## Competitive Moves (Last 30 Days)\\n\\n';\n for (const c of d.competitorMoves) {\n const threatEmoji = c.threat === 'High' ? '\\ud83d\\udd34' : c.threat === 'Medium' ? '\\ud83d\\udfe1' : '\\ud83d\\udfe2';\n page += '- ' + threatEmoji + ' **' + c.company + '** \\u2014 ' + c.summary + ' (' + c.date + ')\\n';\n }\n page += '\\n';\n}\n\n// DRIFT ALERTS\nif (d.alertList && d.alertList.length > 0) {\n page += '## Open Drift Alerts\\n\\n';\n for (const al of d.alertList) {\n const sevEmoji = al.severity === 'Critical' ? '\\ud83d\\udd34' : al.severity === 'High' ? '\\ud83d\\udfe0' : '\\ud83d\\udfe1';\n page += '- ' + sevEmoji + ' **' + al.title + '** \\u2014 ' + al.severity + ' (' + al.status + ')\\n';\n }\n page += '\\n';\n}\n\n// ROADMAP ALIGNMENT\npage += '## Roadmap Alignment\\n\\n';\npage += '| Wave | Timeline | Layers | Community Demand | Issues |\\n';\npage += '|------|----------|--------|-----------------|--------|\\n';\nfor (const w of d.waveAlignment) {\n page += '| **' + w.wave + '** | ' + w.when + ' | ' + w.layers + ' | ' + w.communityDemand + ' | ' + w.issueCount + ' |\\n';\n}\npage += '\\n';\n\n// AI NARRATIVE: MARKET SHIFTS + ROADMAP\npage += '---\\n\\n';\npage += narrative;\npage += '\\n\\n---\\n\\n';\npage += '*This dashboard is auto-generated every 12 hours by the Strategy Command Center workflow.*\\n';\n\nreturn [{ json: { pageContent: page, title: 'Strategy Command Center \\u2014 ' + d.dateStr } }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1900,
600
],
"id": "cc-0001-0019-4000-a000-000000000019",
"name": "Compose Dashboard Page"
},
{
"parameters": {
"resource": "page",
"operation": "update",
"pageId": {
"__rl": true,
"value": "3282d8a2-d60e-81c6-a1e9-d6b98550ac80",
"mode": "id"
},
"title": "={{ $json.title }}",
"body": {
"contentUi": {
"contentValues": [
{
"content": "={{ $json.pageContent }}"
}
]
}
}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
2140,
600
],
"id": "cc-0001-0020-4000-a000-000000000020",
"name": "Update Command Center",
"credentials": {
"notionApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "health-critical",
"leftValue": "={{ $('Build Dashboard Data').first().json.healthLabel }}",
"rightValue": "STABLE",
"operator": {
"type": "string",
"operation": "notEquals"
}
}
],
"combinator": "and"
}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
2140,
800
],
"id": "cc-0001-0021-4000-a000-000000000021",
"name": "Should Notify?"
},
{
"parameters": {
"select": "channel",
"channelId": {
"__rl": true,
"value": "#strategy-signals",
"mode": "name"
},
"text": "={{ '*Strategy Command Center Updated*\\nHealth: ' + $('Build Dashboard Data').first().json.healthLabel + ' (' + $('Build Dashboard Data').first().json.healthScore + '/100)\\nOpen Alerts: ' + $('Build Dashboard Data').first().json.openAlerts + ' | Signals this week: ' + $('Build Dashboard Data').first().json.signals7d + '\\n<https://www.notion.so/3282d8a2d60e81c6a1e9d6b98550ac80|View Dashboard>' }}",
"otherOptions": {
"mrkdwn": true
}
},
"type": "n8n-nodes-base.slack",
"typeVersion": 2.2,
"position": [
2380,
800
],
"id": "cc-0001-0022-4000-a000-000000000022",
"name": "Slack: Command Center Alert",
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Every 12 Hours (Offset)": {
"main": [
[
{
"node": "Fetch Strategy Signals",
"type": "main",
"index": 0
},
{
"node": "Fetch Assumptions",
"type": "main",
"index": 0
},
{
"node": "Fetch Drift Alerts",
"type": "main",
"index": 0
},
{
"node": "Fetch Competitive Intel",
"type": "main",
"index": 0
},
{
"node": "Fetch Metrics",
"type": "main",
"index": 0
}
]
]
},
"Fetch Strategy Signals": {
"main": [
[
{
"node": "Tag: Signals",
"type": "main",
"index": 0
}
]
]
},
"Fetch Assumptions": {
"main": [
[
{
"node": "Tag: Assumptions",
"type": "main",
"index": 0
}
]
]
},
"Fetch Drift Alerts": {
"main": [
[
{
"node": "Tag: Alerts",
"type": "main",
"index": 0
}
]
]
},
"Fetch Competitive Intel": {
"main": [
[
{
"node": "Tag: Competitive",
"type": "main",
"index": 0
}
]
]
},
"Fetch Metrics": {
"main": [
[
{
"node": "Tag: Metrics",
"type": "main",
"index": 0
}
]
]
},
"Tag: Signals": {
"main": [
[
{
"node": "Merge Signals+Assumptions",
"type": "main",
"index": 0
}
]
]
},
"Tag: Assumptions": {
"main": [
[
{
"node": "Merge Signals+Assumptions",
"type": "main",
"index": 1
}
]
]
},
"Tag: Alerts": {
"main": [
[
{
"node": "Merge Alerts+Competitive",
"type": "main",
"index": 0
}
]
]
},
"Tag: Competitive": {
"main": [
[
{
"node": "Merge Alerts+Competitive",
"type": "main",
"index": 1
}
]
]
},
"Merge Signals+Assumptions": {
"main": [
[
{
"node": "Merge Top+Bottom",
"type": "main",
"index": 0
}
]
]
},
"Merge Alerts+Competitive": {
"main": [
[
{
"node": "Merge Top+Bottom",
"type": "main",
"index": 1
}
]
]
},
"Merge Top+Bottom": {
"main": [
[
{
"node": "Merge All Data",
"type": "main",
"index": 0
}
]
]
},
"Tag: Metrics": {
"main": [
[
{
"node": "Merge All Data",
"type": "main",
"index": 1
}
]
]
},
"Merge All Data": {
"main": [
[
{
"node": "Build Dashboard Data",
"type": "main",
"index": 0
}
]
]
},
"Build Dashboard Data": {
"main": [
[
{
"node": "AI Narrative",
"type": "main",
"index": 0
}
]
]
},
"Claude Haiku": {
"ai_languageModel": [
[
{
"node": "AI Narrative",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"AI Narrative": {
"main": [
[
{
"node": "Compose Dashboard Page",
"type": "main",
"index": 0
}
]
]
},
"Compose Dashboard Page": {
"main": [
[
{
"node": "Update Command Center",
"type": "main",
"index": 0
},
{
"node": "Should Notify?",
"type": "main",
"index": 0
}
]
]
},
"Should Notify?": {
"main": [
[
{
"node": "Slack: Command Center Alert",
"type": "main",
"index": 0
}
],
[]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"tags": [
{
"name": "strategy-drift"
},
{
"name": "command-center"
}
],
"meta": {
"templateCredsSetupCompleted": false
}
}
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.
anthropicApinotionApislackOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
[Strategy Drift] Strategy Command Center. Uses notion, agent, lmChatAnthropic, slack. Scheduled trigger; 22 nodes.
Source: https://gist.github.com/mercurialsolo/e0f603aef737a14e82d7530509b31a59 — 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.
Aggregates communication data from Slack, Microsoft Teams, Gmail, GitHub, and Confluence into a single, unified AI-powered analysis workflow designed for quality review and automated documentation upd
Build your own Klue/Crayon alternative: Auto-generate comprehensive competitive battlecards with AI research agents for ~$50/month instead of $1,500+
This n8n workflow automatically prepares comprehensive sales research briefs every morning for your upcoming meetings by analyzing both the companies you're meeting with and the individual attendees.
This n8n template builds an automated daily news digest powered by Claude AI.
This workflow automates engineering governance by deploying a multi-agent AI system that validates designs, checks compliance, optimises safety, and predicts maintenance needs. Designed for engineerin