This workflow follows the HTTP Request → RSS Feed Read 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": "QuorumPulse-v1.1-Single",
"nodes": [
{
"parameters": {},
"id": "b1a2b3c4-1234-5678-9abc-def012345678",
"name": "Manual Trigger",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
240,
300
]
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 6
}
]
}
},
"id": "c1d2e3f4-1234-5678-9abc-def012345679",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
240,
420
]
},
{
"parameters": {
"jsCode": "// Init Inputs and Global Telemetry\nconst rss_feeds = [\n \"https://hnrss.org/frontpage\",\n \"https://www.nasa.gov/rss/dyn/breaking_news.rss\"\n];\nconst topics = [\n \"agentic workflows\",\n \"mcp protocol\",\n \"vector databases\",\n \"prompt injection\",\n \"postgres embeddings\"\n];\nconst config = {\n cache_ttl_minutes: 60,\n dedupe_ttl_days: 14,\n min_score: 8,\n max_items_total: 35,\n max_per_source: 12,\n max_per_topic: 6,\n enable_llm_summary: true,\n retry_max: 2,\n retry_backoff_ms: 800,\n timeout_ms: 12000,\n ZAI_API_KEY: $env.ZAI_API_KEY || \"\",\n ZAI_BASE_URL: $env.ZAI_BASE_URL || \"https://api.z.ai/api/paas/v4\",\n ZAI_MODEL: $env.ZAI_MODEL || \"glm-5\"\n};\n\n// Init Telemetry\nconst st = $getWorkflowStaticData('global');\nst.runs = (st.runs || 0) + 1;\n\nreturn [{ json: { rss_feeds, topics, config } }];"
},
"id": "d1e2f3a4-1234-5678-9abc-def01234567a",
"name": "Init",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
360
]
},
{
"parameters": {
"fieldToSplitOut": "rss_feeds",
"destinationFieldName": "rss_url",
"options": {}
},
"id": "e1f2a3b4-1234-5678-9abc-def01234567b",
"name": "Split Out RSS",
"type": "n8n-nodes-base.splitOut",
"typeVersion": 1,
"position": [
660,
240
]
},
{
"parameters": {
"url": "={{ $json.rss_url }}",
"options": {}
},
"id": "f2a3b4c5-1234-5678-9abc-def01234567c",
"name": "RSS Feed Read",
"type": "n8n-nodes-base.rssFeedRead",
"typeVersion": 1,
"position": [
880,
240
]
},
{
"parameters": {
"jsCode": "// Normalize RSS Items - rssFeedRead outputs items directly\nconst items = $input.all();\nconst out = [];\n\nfor(const item of items) {\n const feedUrl = item.json.rss_url;\n // rssFeedRead returns items array directly in item.json\n const entries = Array.isArray(item.json) ? item.json : (item.json.items || []);\n \n for(const entry of entries) {\n const title = entry?.title || \"Untitled\";\n const url = entry?.link || entry?.url || entry?.guid || \"\";\n if(!url) continue;\n \n out.push({\n json: {\n source: \"rss\",\n topic: null,\n title,\n url,\n published_at: entry?.pubDate || entry?.isoDate || entry?.published || null,\n raw_score: 5,\n score: 5,\n summary_raw: entry?.contentSnippet || entry?.description || entry?.summary || null,\n summary: null,\n meta: {\n author: entry?.creator || entry?.author || null,\n venue: feedUrl ? new URL(feedUrl).hostname : 'rss',\n cached: false,\n http_status: null\n }\n }\n });\n }\n}\n\nif (out.length === 0) {\n return [{ json: { __empty: true, __stream: 'rss' } }];\n}\nreturn out;"
},
"id": "a3b4c5d6-1234-5678-9abc-def01234567d",
"name": "Normalize RSS",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1100,
240
]
},
{
"parameters": {
"fieldToSplitOut": "topics",
"destinationFieldName": "topic",
"options": {}
},
"id": "b4c5d6e7-1234-5678-9abc-def01234567e",
"name": "Split Out Topics",
"type": "n8n-nodes-base.splitOut",
"typeVersion": 1,
"position": [
660,
480
]
},
{
"parameters": {
"jsCode": "// Cache Gate Logic\nconst item = $input.first();\nconst topic = item.json.topic;\nconst config = $('Init').first().json.config;\nconst st = $getWorkflowStaticData('global');\n\nif(!st.cache) st.cache = {};\nconst now = Date.now();\nconst ttl = config.cache_ttl_minutes * 60 * 1000;\n\n// Prune old cache entries\nfor(const k in st.cache) {\n if(now - st.cache[k].ts_epoch_ms > ttl) delete st.cache[k];\n}\n\nconst cached = st.cache[topic];\nif(cached && (now - cached.ts_epoch_ms <= ttl)) {\n return [{ json: { topic, config, cache_hit: true, cached_items: cached.items || [] } }];\n}\n\nreturn [{ json: { topic, config, cache_hit: false } }];"
},
"id": "c5d6e7f8-1234-5678-9abc-def01234567f",
"name": "Cache Gate",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
880,
480
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"leftValue": "={{ $json.cache_hit }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "d6e7f8a9-1234-5678-9abc-def012345680",
"name": "IF Cache Hit",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1100,
480
]
},
{
"parameters": {
"jsCode": "const data = $input.first().json;\nconst items = data.cached_items || [];\n\nif (items.length === 0) {\n return [{ json: { __empty: true, __stream: 'cache', __meta: { cached_hits: 0 } } }];\n}\n\nreturn items.map(i => ({\n json: { ...i, meta: { ...i.meta, cached: true }, __meta: { cached_hits: items.length } }\n}));"
},
"id": "e7f8a9b0-1234-5678-9abc-def012345681",
"name": "Emit Cached Items",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1320,
400
]
},
{
"parameters": {
"url": "={{ 'https://hn.algolia.com/api/v1/search?query=' + encodeURIComponent($('Cache Gate').first().json.topic) + '&tags=story&hitsPerPage=5' }}",
"headerParameters": {
"parameters": [
{
"name": "Accept",
"value": "application/json"
}
]
},
"options": {
"timeout": 12000,
"response": {
"response": {
"responseFormat": "json",
"neverError": true
}
}
}
},
"id": "f8a9b0c1-1234-5678-9abc-def012345682",
"name": "Fetch HN",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1320,
560
]
},
{
"parameters": {
"url": "={{ 'https://api.github.com/search/repositories?q=' + encodeURIComponent($('Cache Gate').first().json.topic) + '&sort=updated&order=desc&per_page=5' }}",
"headerParameters": {
"parameters": [
{
"name": "Accept",
"value": "application/vnd.github+json"
},
{
"name": "User-Agent",
"value": "n8n-quorumpulse"
}
]
},
"options": {
"timeout": 12000,
"response": {
"response": {
"responseFormat": "json",
"neverError": true
}
}
}
},
"id": "a9b0c1d2-1234-5678-9abc-def012345683",
"name": "Fetch GitHub",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1320,
680
]
},
{
"parameters": {
"url": "={{ 'https://api.crossref.org/works?query=' + encodeURIComponent($('Cache Gate').first().json.topic) + '&rows=5' }}",
"options": {
"timeout": 12000,
"response": {
"response": {
"responseFormat": "json",
"neverError": true
}
}
}
},
"id": "b0c1d2e3-1234-5678-9abc-def012345684",
"name": "Fetch Crossref",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1320,
800
]
},
{
"parameters": {
"jsCode": "const topic = $('Cache Gate').first().json.topic;\nconst data = $input.first().json;\nconst hits = data?.hits || [];\n\nif (!hits || hits.length === 0) {\n return [{ json: { __empty: true, __src: 'hn', __meta: { failed_calls: data ? 0 : 1 } } }];\n}\n\nreturn hits.map(h => ({\n json: {\n source: \"hn\",\n topic,\n title: h.title || \"Untitled\",\n url: h.url || `https://news.ycombinator.com/item?id=${h.objectID}`,\n published_at: h.created_at ? new Date(h.created_at).toISOString() : null,\n raw_score: (h.points || 0) + (h.num_comments || 0),\n score: (h.points || 0) + (h.num_comments || 0),\n summary_raw: null,\n summary: null,\n meta: { author: h.author || null, venue: \"HackerNews\", cached: false, http_status: null }\n }\n}));"
},
"id": "d2e3f4a5-1234-5678-9abc-def012345686",
"name": "Normalize HN",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1540,
560
]
},
{
"parameters": {
"jsCode": "const topic = $('Cache Gate').first().json.topic;\nconst data = $input.first().json;\nconst items = data?.items || [];\n\nif (!items || items.length === 0) {\n return [{ json: { __empty: true, __src: 'github', __meta: { failed_calls: data ? 0 : 1 } } }];\n}\n\nreturn items.map(i => ({\n json: {\n source: \"github\",\n topic,\n title: i.full_name || i.name || \"Untitled\",\n url: i.html_url || \"\",\n published_at: i.updated_at || null,\n raw_score: (i.stargazers_count||0) + (i.forks_count||0),\n score: (i.stargazers_count||0) + (i.forks_count||0),\n summary_raw: i.description || null,\n summary: null,\n meta: { author: i.owner?.login || null, venue: \"GitHub\", cached: false, http_status: null }\n }\n}));"
},
"id": "e3f4a5b6-1234-5678-9abc-def012345687",
"name": "Normalize GitHub",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1540,
680
]
},
{
"parameters": {
"jsCode": "const topic = $('Cache Gate').first().json.topic;\nconst data = $input.first().json;\nconst items = data?.message?.items || [];\n\nif (!items || items.length === 0) {\n return [{ json: { __empty: true, __src: 'crossref', __meta: { failed_calls: data ? 0 : 1 } } }];\n}\n\nreturn items.map(i => {\n const title = (i.title && i.title[0]) || \"Untitled\";\n const url = i.URL || (i.DOI ? `https://doi.org/${i.DOI}` : \"\");\n return {\n json: {\n source: \"crossref\",\n topic,\n title,\n url,\n published_at: i.published?.['date-parts']?.[0]?.join('-') || null,\n raw_score: 20 + (i['is-referenced-by-count']||0),\n score: 20 + (i['is-referenced-by-count']||0),\n summary_raw: i.abstract || i.subtitle || null,\n summary: null,\n meta: { author: null, venue: i['container-title']?.[0] || \"Crossref\", cached: false, http_status: null }\n }\n };\n});"
},
"id": "f4a5b6c7-1234-5678-9abc-def012345688",
"name": "Normalize Crossref",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1540,
800
]
},
{
"parameters": {
"mode": "append"
},
"id": "a5b6c7d8-1234-5678-9abc-def012345689",
"name": "Merge HN+GitHub",
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
1760,
620
]
},
{
"parameters": {
"mode": "append"
},
"id": "b6c7d8e9-1234-5678-9abc-def01234568a",
"name": "Merge (prev)+Crossref",
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
1980,
680
]
},
{
"parameters": {
"jsCode": "const allInputs = $input.all();\nconst topic = $('Cache Gate').first().json.topic;\nconst st = $getWorkflowStaticData('global');\n\nif(!st.cache) st.cache = {};\n\n// Collect valid items (skip __empty markers)\nlet failedCalls = 0;\nconst validItems = [];\n\nfor (const item of allInputs) {\n const i = item.json;\n if (i.__empty) {\n if (i.__meta?.failed_calls) failedCalls += i.__meta.failed_calls;\n continue;\n }\n validItems.push(i);\n}\n\n// Save to cache (even if empty)\nst.cache[topic] = { ts_epoch_ms: Date.now(), items: validItems };\n\nif (validItems.length === 0) {\n return [{ json: { __empty: true, topic, __meta: { api_calls: 3, failed_calls: failedCalls || 3 } } }];\n}\n\nreturn validItems.map(i => ({ json: { ...i, __meta: { api_calls: 3, failed_calls: 0 } } }));"
},
"id": "c7d8e9f0-1234-5678-9abc-def01234568b",
"name": "Cache Save",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2200,
600
]
},
{
"parameters": {
"mode": "append"
},
"id": "d8e9f0a1-1234-5678-9abc-def01234568c",
"name": "Topic Output Join",
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
2420,
500
]
},
{
"parameters": {
"mode": "append"
},
"id": "e9f0a1b2-1234-5678-9abc-def01234568d",
"name": "Merge All Streams",
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
2640,
370
]
},
{
"parameters": {
"jsCode": "const init = $('Init').first().json;\nconst config = init.config;\nconst st = $getWorkflowStaticData('global');\nif(!st.seen) st.seen = {};\n\nconst now = Date.now();\nconst dedupeTtl = config.dedupe_ttl_days * 24 * 60 * 60 * 1000;\n\n// Prune seen\nfor(const k in st.seen) {\n if(now - st.seen[k] > dedupeTtl) delete st.seen[k];\n}\n\n// Collect all items and count cache misses\nlet candidates = 0;\nlet cachedHits = 0;\nlet apiCalls = 0;\nlet failedCalls = 0;\nconst allItems = [];\n\nfor (const item of $input.all()) {\n const i = item.json;\n \n // Skip empty markers but extract stats\n if (i.__empty) {\n if (i.__meta?.failed_calls) failedCalls += i.__meta.failed_calls;\n continue;\n }\n \n candidates++;\n \n // Count cached hits\n if (i.meta?.cached) cachedHits++;\n \n // Count API calls from metadata\n if (i.__meta?.api_calls) apiCalls += i.__meta.api_calls;\n if (i.__meta?.failed_calls) failedCalls += i.__meta.failed_calls;\n \n allItems.push(i);\n}\n\n// Dedupe\nconst seen = [];\nfor (const i of allItems) {\n if(!i.url) continue;\n if(st.seen[i.url]) continue;\n st.seen[i.url] = now;\n seen.push(i);\n}\n\n// Filter Score\nconst filtered = seen.filter(i => i.score >= config.min_score);\n\n// Sort by score first (best items survive caps)\nfiltered.sort((a,b) => b.score - a.score);\n\n// Diversity Caps (check BEFORE incrementing)\nconst sourceCounts = {};\nconst topicCounts = {};\nconst capped = [];\n\nfor (const i of filtered) {\n const s = i.source || 'unknown';\n const t = i.topic || 'null';\n \n // Check caps first\n if((sourceCounts[s] || 0) >= config.max_per_source) continue;\n if((topicCounts[t] || 0) >= config.max_per_topic) continue;\n \n // Then increment\n sourceCounts[s] = (sourceCounts[s] || 0) + 1;\n topicCounts[t] = (topicCounts[t] || 0) + 1;\n capped.push(i);\n}\n\n// Final slice\nconst items = capped.slice(0, config.max_items_total);\n\n// Stats\nconst stats = {\n candidates_total: candidates,\n new_items: items.length,\n cached_hits: cachedHits,\n api_calls: apiCalls,\n failed_calls: failedCalls,\n by_source: items.reduce((acc, i) => { acc[i.source] = (acc[i.source]||0)+1; return acc; }, {})\n};\n\nreturn [{ json: { config, topics: init.topics, stats, items, run_id: st.runs, generated_at: new Date().toISOString() } }];"
},
"id": "f0a1b2c3-1234-5678-9abc-def01234568e",
"name": "Finalize",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2860,
370
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"leftValue": "={{ $json.config.enable_llm_summary }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
},
{
"leftValue": "={{ $json.config.ZAI_API_KEY }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "isNotEmpty"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "a1b2c3d4-1234-5678-9abc-def01234568f",
"name": "IF LLM",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
3080,
370
]
},
{
"parameters": {
"jsCode": "const ctx = $input.first().json;\nconst top12 = (ctx.items || []).slice(0, 12).map(i => `URL: ${i.url}\\nTitle: ${i.title}\\nScore: ${i.score}`).join('\\n\\n');\nconst prompt = `Generate a 1 sentence summary for each of the following items. Return STRICT JSON:\\n{\"summaries\":[{\"url\":\"...\",\"summary\":\"1 sentence\"}]}\\n\\nItems:\\n${top12}`;\nreturn [{ json: {\n // Preserve base data\n __baseData: {\n config: ctx.config,\n topics: ctx.topics,\n stats: ctx.stats,\n run_id: ctx.run_id,\n generated_at: ctx.generated_at,\n items: ctx.items\n },\n config: ctx.config,\n llm_body: { messages: [{ role: 'user', content: prompt }] }\n} }];"
},
"id": "b2c3d4e5-1234-5678-9abc-def012345690",
"name": "Prepare LLM",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
3300,
280
]
},
{
"parameters": {
"url": "={{ $json.config.ZAI_BASE_URL + '/chat/completions' }}",
"authentication": "none",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "={{ 'Bearer ' + $json.config.ZAI_API_KEY }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ model: $json.config.ZAI_MODEL, messages: $json.llm_body.messages, response_format: {type:'json_object'}, temperature: 0.2 }) }}",
"options": {
"response": {
"response": {
"responseFormat": "json",
"neverError": true
}
}
}
},
"id": "c3d4e5f6-1234-5678-9abc-def012345691",
"name": "LLM HTTP",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
3520,
280
]
},
{
"parameters": {
"jsCode": "// CRITICAL: Read base data from Prepare LLM (not from HTTP response)\nconst prepNode = $('Prepare LLM').first().json;\nconst baseData = prepNode.__baseData || prepNode;\nconst resp = $input.first().json;\n\nlet summaryMap = {};\n\ntry {\n let content = resp?.choices?.[0]?.message?.content;\n if(content) {\n const parsed = JSON.parse(content);\n // Support both formats: {summaries:[]} and {\"url\":\"summary\"}\n if (Array.isArray(parsed.summaries)) {\n parsed.summaries.forEach(s => { if(s.url && s.summary) summaryMap[s.url] = s.summary; });\n } else if (typeof parsed === 'object') {\n for (const [url, summary] of Object.entries(parsed)) {\n if (typeof summary === 'string') summaryMap[url] = summary;\n }\n }\n }\n} catch(e) { console.error('LLM parse error:', e); }\n\nconst items = (baseData.items || []).map(i => ({\n ...i,\n summary: summaryMap[i.url] || i.summary_raw || i.title\n}));\n\nreturn [{ json: {\n config: baseData.config,\n topics: baseData.topics,\n stats: baseData.stats,\n run_id: baseData.run_id,\n generated_at: baseData.generated_at,\n items\n} }];"
},
"id": "d4e5f6a7-1234-5678-9abc-def012345692",
"name": "Apply Summaries",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
3740,
280
]
},
{
"parameters": {
"jsCode": "const ctx = $input.first().json;\nconst items = (ctx.items || []).map(i => ({\n ...i,\n summary: i.summary_raw || i.title\n}));\nreturn [{ json: { ...ctx, items } }];"
},
"id": "e5f6a7b8-1234-5678-9abc-def012345693",
"name": "Fallback Summary",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
3300,
460
]
},
{
"parameters": {
"jsCode": "const data = $input.first().json;\n// QA Checks\nif(!data.items || !Array.isArray(data.items)) throw new Error('Invalid items');\nfor(const i of data.items) {\n if(typeof i.url !== 'string' || i.url === '') throw new Error('Empty URL');\n if(typeof i.score !== 'number') throw new Error('Invalid score');\n}\nconst str = JSON.stringify(data);\nif(str.includes('{{')) throw new Error('Contains {{');\nreturn [{ json: data }];"
},
"id": "f6a7b8c9-1234-5678-9abc-def012345694",
"name": "QA Lint",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
3960,
370
]
},
{
"parameters": {
"jsCode": "const data = $input.first().json;\nconst bySource = {};\n(data.items || []).forEach(i => {\n if(!bySource[i.source]) bySource[i.source] = [];\n bySource[i.source].push(i);\n});\n\nlet md = `# QuorumPulse Signal Pack\\n\\n`;\nmd += `**Generated:** ${data.generated_at}\\n`;\nmd += `**Stats:** ${data.stats?.new_items || 0} items, ${data.stats?.cached_hits || 0} cached, ${data.stats?.api_calls || 0} API calls\\n\\n`;\n\nfor(const [src, items] of Object.entries(bySource)) {\n md += `## ${src.toUpperCase()}\\n`;\n items.forEach(i => {\n md += `- [${i.score}] ${i.title}\\n > ${i.summary || 'No summary'}\\n Link: ${i.url}\\n`;\n });\n md += `\\n`;\n}\n\nreturn [{ json: { ...data, digest_markdown: md } }];"
},
"id": "a7b8c9d0-1234-5678-9abc-def012345695",
"name": "Build Final",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
4180,
370
]
}
],
"connections": {
"Manual Trigger": {
"main": [
[
{
"node": "Init",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Init",
"type": "main",
"index": 0
}
]
]
},
"Init": {
"main": [
[
{
"node": "Split Out RSS",
"type": "main",
"index": 0
},
{
"node": "Split Out Topics",
"type": "main",
"index": 0
}
]
]
},
"Split Out RSS": {
"main": [
[
{
"node": "RSS Feed Read",
"type": "main",
"index": 0
}
]
]
},
"RSS Feed Read": {
"main": [
[
{
"node": "Normalize RSS",
"type": "main",
"index": 0
}
]
]
},
"Split Out Topics": {
"main": [
[
{
"node": "Cache Gate",
"type": "main",
"index": 0
}
]
]
},
"Cache Gate": {
"main": [
[
{
"node": "IF Cache Hit",
"type": "main",
"index": 0
}
]
]
},
"IF Cache Hit": {
"main": [
[
{
"node": "Emit Cached Items",
"type": "main",
"index": 0
}
],
[
{
"node": "Fetch HN",
"type": "main",
"index": 0
},
{
"node": "Fetch GitHub",
"type": "main",
"index": 0
},
{
"node": "Fetch Crossref",
"type": "main",
"index": 0
}
]
]
},
"Emit Cached Items": {
"main": [
[
{
"node": "Topic Output Join",
"type": "main",
"index": 0
}
]
]
},
"Fetch HN": {
"main": [
[
{
"node": "Normalize HN",
"type": "main",
"index": 0
}
]
]
},
"Fetch GitHub": {
"main": [
[
{
"node": "Normalize GitHub",
"type": "main",
"index": 0
}
]
]
},
"Fetch Crossref": {
"main": [
[
{
"node": "Normalize Crossref",
"type": "main",
"index": 0
}
]
]
},
"Normalize HN": {
"main": [
[
{
"node": "Merge HN+GitHub",
"type": "main",
"index": 0
}
]
]
},
"Normalize GitHub": {
"main": [
[
{
"node": "Merge HN+GitHub",
"type": "main",
"index": 1
}
]
]
},
"Merge HN+GitHub": {
"main": [
[
{
"node": "Merge (prev)+Crossref",
"type": "main",
"index": 0
}
]
]
},
"Normalize Crossref": {
"main": [
[
{
"node": "Merge (prev)+Crossref",
"type": "main",
"index": 1
}
]
]
},
"Merge (prev)+Crossref": {
"main": [
[
{
"node": "Cache Save",
"type": "main",
"index": 0
}
]
]
},
"Cache Save": {
"main": [
[
{
"node": "Topic Output Join",
"type": "main",
"index": 1
}
]
]
},
"Topic Output Join": {
"main": [
[
{
"node": "Merge All Streams",
"type": "main",
"index": 1
}
]
]
},
"Normalize RSS": {
"main": [
[
{
"node": "Merge All Streams",
"type": "main",
"index": 0
}
]
]
},
"Merge All Streams": {
"main": [
[
{
"node": "Finalize",
"type": "main",
"index": 0
}
]
]
},
"Finalize": {
"main": [
[
{
"node": "IF LLM",
"type": "main",
"index": 0
}
]
]
},
"IF LLM": {
"main": [
[
{
"node": "Prepare LLM",
"type": "main",
"index": 0
}
],
[
{
"node": "Fallback Summary",
"type": "main",
"index": 0
}
]
]
},
"Prepare LLM": {
"main": [
[
{
"node": "LLM HTTP",
"type": "main",
"index": 0
}
]
]
},
"LLM HTTP": {
"main": [
[
{
"node": "Apply Summaries",
"type": "main",
"index": 0
}
]
]
},
"Apply Summaries": {
"main": [
[
{
"node": "QA Lint",
"type": "main",
"index": 0
}
]
]
},
"Fallback Summary": {
"main": [
[
{
"node": "QA Lint",
"type": "main",
"index": 0
}
]
]
},
"QA Lint": {
"main": [
[
{
"node": "Build Final",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
QuorumPulse-v1.1-Single. Uses rssFeedRead, httpRequest. Event-driven trigger; 29 nodes.
Source: https://github.com/turtir-ai/n8n-workflow-studio/blob/main/public/fixtures/QuorumPulse-v1.1-Single.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.
GoldPulse-v1.1-Single. Uses rssFeedRead, httpRequest. Event-driven trigger; 33 nodes.
AegisPulse-v1.1-Single. Uses rssFeedRead, httpRequest. Event-driven trigger; 31 nodes.
PulseMosaic-v2-Single. Uses rssFeedRead, httpRequest. Event-driven trigger; 25 nodes.
PulseMosaic-v3.1-Single. Uses rssFeedRead, httpRequest. Event-driven trigger; 25 nodes.
SignalForge-v2.1-gold. Uses httpRequest, rssFeedRead. Event-driven trigger; 24 nodes.