{
 "name": "RecipeAgents: Daily Slack channel digest with Claude",
 "nodes": [
  {
   "parameters": {
    "rule": {
     "interval": [
      {
       "field": "weeks",
       "triggerAtDay": [
        1,
        2,
        3,
        4,
        5
       ],
       "triggerAtHour": 8
      }
     ]
    }
   },
   "id": "37718a5f-88c0-596b-8b3f-e7bfb05c87ab",
   "name": "Schedule Trigger",
   "type": "n8n-nodes-base.scheduleTrigger",
   "typeVersion": 1.2,
   "position": [
    240,
    300
   ]
  },
  {
   "parameters": {
    "resource": "channel",
    "operation": "history",
    "channelId": {
     "__rl": true,
     "value": "",
     "mode": "list"
    },
    "returnAll": true,
    "filters": {
     "oldest": "={{ $now.minus({ hours: $now.weekday === 1 ? 72 : 24 }).toISO() }}"
    }
   },
   "id": "300dea43-ca94-5ca7-9674-8dbcf3cb0a41",
   "name": "Get channel history",
   "type": "n8n-nodes-base.slack",
   "typeVersion": 2.7,
   "position": [
    500,
    300
   ]
  },
  {
   "parameters": {
    "jsCode": "// Turns the channel history into one transcript for Claude.\n// Drops joins, bot posts and empty messages, sorts oldest first,\n// marks messages that started a thread, keeps the newest 60,000 characters.\nconst MAX_CHARS = 60000;\nconst msgs = $input.all().map(i => i.json)\n  .filter(m => !m.subtype && !m.bot_id && String(m.text || '').trim())\n  .sort((a, b) => Number(a.ts) - Number(b.ts));\nif (msgs.length === 0) return [];  // quiet day: nothing is posted\nconst lines = msgs.map(m => {\n  const time = DateTime.fromSeconds(Number(m.ts)).toFormat('HH:mm');\n  const thread = m.reply_count ? ` [thread: ${m.reply_count} replies not shown]` : '';\n  return `[${time}] <@${m.user}>: ${String(m.text).replace(/\\s+/g, ' ')}${thread}`;\n});\nlet transcript = lines.join('\\n');\nif (transcript.length > MAX_CHARS) transcript = '(older messages cut)\\n' + transcript.slice(-MAX_CHARS);\nreturn [{ json: { transcript, message_count: msgs.length } }];"
   },
   "id": "67088813-eaaa-5b1d-ad6d-12417bad54c0",
   "name": "Build transcript",
   "type": "n8n-nodes-base.code",
   "typeVersion": 2,
   "position": [
    760,
    300
   ]
  },
  {
   "parameters": {
    "resource": "text",
    "operation": "message",
    "modelId": {
     "__rl": true,
     "value": "claude-haiku-5-5",
     "mode": "id"
    },
    "messages": {
     "values": [
      {
       "content": "=You write a short daily digest of one Slack channel for people who missed the day. Below are the top-level messages from the period, oldest first. Each line is [time] <@user ID>: text.\nWrite the digest in Slack formatting with these sections, and leave out any section that would be empty:\n*Decided*: decisions that were made, one bullet each\n*Needs an answer*: questions nobody has answered yet\n*Action items*: who will do what, with a due date only if one was stated\n*FYI*: anything else worth knowing, at most 3 bullets\nRefer to people exactly as they appear, like <@U0123ABC>. Use only what is in the messages: don't guess owners or dates. A line ending in [thread: N replies not shown] started a thread you can't see, so don't say how it ended. Keep it under 200 words. No greeting and no sign-off.\n\nMessages:\n{{ $json.transcript }}",
       "role": "user"
      }
     ]
    },
    "simplify": true,
    "options": {
     "includeMergedResponse": true,
     "maxTokens": 1500
    }
   },
   "id": "bc209afb-baad-56af-8093-0c2500130f17",
   "name": "Claude: write digest",
   "type": "@n8n/n8n-nodes-langchain.anthropic",
   "typeVersion": 1,
   "position": [
    1020,
    300
   ]
  },
  {
   "parameters": {
    "select": "channel",
    "channelId": {
     "__rl": true,
     "value": "",
     "mode": "list"
    },
    "text": "=*Channel digest* ({{ $('Build transcript').item.json.message_count }} messages)\n{{ $json.merged_response }}",
    "otherOptions": {
     "includeLinkToWorkflow": false
    }
   },
   "id": "cddcbd15-fcdf-5847-8a6e-7241b8f36d5c",
   "name": "Post digest",
   "type": "n8n-nodes-base.slack",
   "typeVersion": 2.7,
   "position": [
    1280,
    300
   ]
  },
  {
   "parameters": {
    "content": "## Daily Slack channel digest with Claude\nFrom recipeagents.usestarbase.com/recipes/slack-channel-digest-claude\n\n1. Connect credentials on each node (Slack on both Slack nodes (your own app with channels:history and chat:write), Anthropic).\n2. Pick your sheet/folder/channel and model.\n3. Run once with test data and check the output before activating.\nKeep a human check on anything customer-facing.",
    "height": 260,
    "width": 420
   },
   "id": "75ac8bed-154c-5a3e-b365-5130f7b08f52",
   "name": "Read me",
   "type": "n8n-nodes-base.stickyNote",
   "typeVersion": 1,
   "position": [
    200,
    20
   ]
  }
 ],
 "connections": {
  "Schedule Trigger": {
   "main": [
    [
     {
      "node": "Get channel history",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Get channel history": {
   "main": [
    [
     {
      "node": "Build transcript",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Build transcript": {
   "main": [
    [
     {
      "node": "Claude: write digest",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Claude: write digest": {
   "main": [
    [
     {
      "node": "Post digest",
      "type": "main",
      "index": 0
     }
    ]
   ]
  }
 },
 "pinData": {},
 "active": false,
 "settings": {
  "executionOrder": "v1"
 },
 "meta": {
  "templateCredsSetupCompleted": false
 },
 "tags": []
}