Skip to content
All session materials

IIM Calcutta, DigiAIM 12 ·

Session 2 — The Content Engine · Prompts & Activities

Pillars → 30-day production queue → Flow & HeyGen briefs → your first n8n agent with an approval gate.

Pillars → 30-day production queue → Flow & HeyGen briefs → your first n8n agent with an approval gate.
Saturday, 12 September 2026 6:45 – 9:45 PM IST · Zoom Part 1 · Part 2 · break · Part 3 Faculty: Siddhesh Joglekar

How to use this sheet

  • Every prompt follows CRISP. Replace everything in [brackets] with your real details. The template is scaffolding; the specifics are the skill.
  • Work one job at a time, and argue back at every approval gate — zero pushback means you didn't read.
  • Tonight's floor: a 30-day calendar + one video brief + your agent run once with the approval gate. Everything else is bonus.
  • Keep this file open beside the workbook (Session2_Workbook.xlsx) — prompts here, answers there.

The CRISP framework — how we prompt, every time

CContextWho you are, whom you serve, your positioning from Session 1, the goal action.
RRoleThe expert hat the AI wears (social strategist, shot director, speechwriter).
IInstructionsThe task, sequenced — with STOP points where your approval gates the next step.
SSpecificsFormats, counts, word limits, UTM links, the 8–12 concept rule.
PPain pointsWhat must never happen: invented stats, ad-speak, broken naming conventions.
A CRISP prompt is a brief, not a wish. The brief is where the quality is decided.
Part 1 · 7:15 PM · Build 1

Prompt 1 — The calendar prompt: pillars → matrix → 30-day queue

Where: Claude / ChatGPT / Gemini · Time: 15 min · Lands in: workbook tabs Pillar_Format_Matrix + Calendar_30day
Run it in stages. When it proposes pillars — STOP, argue, reject at least one. Wrong pillars = 30 wrong rows.
C — CONTEXT
I run [brand]. Positioning (from my site brief): [one line — who you help, to what outcome].
My one named reader: [person, age, role, city, when they scroll — from the pre-read worksheet].
My site: [URL]. The action I want from every post: a click to my site.

R — ROLE
You are a social content strategist for Indian [B2C / B2B] brands who builds
repeatable engines, not viral one-offs.

I — INSTRUCTIONS (in stages; wait for my "go" between each)
Stage 1: Propose 3–4 content pillars. A pillar is an ARGUMENT my brand repeats
until it sticks, not a topic. For each: the argument in one sentence, why my
named reader cares, and one example post idea. STOP for my approval.
Stage 2: Build the pillar × format matrix (formats: Reel, carousel, LinkedIn
text, avatar video, WhatsApp broadcast). Mark frequency per cell — or a dash.
Dashes are decisions. STOP for my approval.
Stage 3: Generate the 30-day calendar, 14 Sep – 13 Oct 2026, as a table:
date · pillar · format · hook (written out in full — the actual first line) ·
CTA (one action). Weekdays my reader actually scrolls, not all 30 days.

S — SPECIFICS
8–12 distinct CONCEPTS across the month, 2–3 variants each — never 25 versions
of one idea. At least one pillar must be proof (customer evidence), not promotion.
Offers capped at 20% of posts. Every post will carry a UTM link I add myself.

P — PAIN POINTS (never do these)
No invented statistics, customer names, or claims — if you need a number, leave
a [MY NUMBER] placeholder. No ad-speak ("Unlock!", "Game-changer"). Hooks in my
voice: [2 lines you'd actually say + 1 line you'd never say].
Watch out
  • If every matrix cell is filled, nothing is a priority. Demand dashes.
  • Hooks like "5 tips for..." are topics wearing a hat. Send them back: "rewrite as the first line I would actually post."
Then: copy the approved matrix into the workbook tab, and the calendar's week one into Calendar_30day rows 6–12. UTM links come from Prompt 2's naming discipline.
Part 1 · 7:35 PM · Build 1

Prompt 2 — Week one, drafted: 5–7 posts in your voice

Where: same chat, after Prompt 1 · Time: 10 min · Lands in: Calendar_30day hooks + your drafts doc
Build your UTM links FIRST in the workbook's UTM_Naming_Sheet — the drafts must carry the final links.
Using the approved calendar, fully draft week one (the first 5–7 posts).

For each post give me:
1. The post, complete and ready to publish, in the format's limits:
   Reel caption ≤ 125 words + 5 hashtags · LinkedIn ≤ 200 words, no hashtag
   in line 1 · carousel = 6 slide texts of ≤ 20 words · WhatsApp ≤ 60 words.
2. The hook exactly as approved in the calendar (tighten, don't replace).
3. My UTM link placed where the CTA points: [paste the link for this row
   from your UTM_Naming_Sheet]
4. One line: "WHY THIS WORKS:" — the hook's logic in ≤ 15 words.

Rules: no invented statistics or claims (leave [MY NUMBER] placeholders);
one CTA per post; write for the ear on video scripts.
Draft posts one at a time. After each, wait — I will say "next" or redline it.
Keep every redline you make. Your edits tonight become your agent's system-prompt rules at 8:45 — you are collecting its employment contract clause by clause.
Part 2 · 8:07 PM · Write it

Prompt 3 — The Flow shot-list brief: one row becomes 8 seconds of film

Where: any frontier chat, then paste the result into Google Flow (labs.google/flow) · Time: 4 min · Lands in: workbook tab Flow_ShotList_Template
Generation is homework (free tier: 50 credits/day — draft on Veo Fast, render once on Quality). Tonight you write the brief.
C — I'm turning this calendar row into an 8-second Veo clip in Google Flow:
[date · pillar · format · hook — paste the row]. The clip's one job: [stop the
scroll for saves / make one number feel real / show the product in use].
R — You are a film director who briefs AI video models with shot lists,
not adjectives.
I — Write my Flow shot list with exactly these fields:
SUBJECT (one thing) · ACTION (one beat, physical, filmable) · SETTING
(place, time of day, depth) · CAMERA (one move) · LIGHT + AUDIO (mood,
ambience — no dialogue) · NEGATIVES (what must never appear).
Then list the 2–3 INGREDIENT photos of my real product I should upload
so the brand stays consistent across shots.
S — Vertical 9:16 [or 1:1 / 16:9 per the format]. India-plausible setting.
On-screen text is NOT generated — tell me the overlay line I add in my editor.
P — No faces unless I say so. No logos I don't own. No text baked into
the render. Nothing on screen that makes a claim I can't prove.
Watch out
  • One subject, one action, one camera move. If the shot list has two beats, it's two clips — use Extend.
  • Run the Howrah pass on the render before posting: setting plausible? objects yours? claims provable?
Part 2 · 8:10 PM · Write it

Prompt 4 — The HeyGen script: 60 founder-voice seconds

Where: any frontier chat, then paste into HeyGen · Time: 4 min · Lands in: workbook tab HeyGen_Script_Template
Read the result ALOUD once before generating. If you stumble, the avatar stumbles forever.
C — I'm scripting a 60-second avatar video of myself for this calendar row:
[date · pillar · hook — paste the row]. Audience: [your named reader].
The one action I want: [CTA from the row].
R — You are a speechwriter for founders. You write for the EAR: short
sentences, contractions, natural rhythm — never essay prose.
I — Write the script in this frame, ~140 words total:
HOOK (0–5s): name the viewer's question. No greeting.
STAKES (5–15s): why it matters to THEM — one concrete number or moment.
POINT 1 / POINT 2 (15–41s): two things that worked. Lead with verbs.
POINT 3 (41–50s): the honest one — what didn't work. This earns the follow.
CTA (50–60s): the one action, said plainly.
S — Sentences ≤ 12 words. My real numbers only: [paste 2–3 real numbers
you're willing to say on camera]. Leave one imperfect, human line in.
P — Nothing I haven't actually done. No "guys". No hype adjectives. And
remind me at the end: on-screen label "AI-generated avatar of a real
person" for the full duration — ASCI draft rules, and my own trust.
Free-tier plan: 3 watermarked one-minute videos a month — test with a stock avatar first, spend your best take on yourself. Your digital twin (15-sec video + 1 photo) is this week's homework.
Part 3 · 8:45 PM · Build 2 · Live

Activity 5 — Import and run your first agent (the JSON is below)

Where: your n8n Cloud workspace (free trial) · Time: 25–30 min · Lands in: a running agent + workbook tab Agent_Run_Log
Red credential boxes after import are NORMAL, not broken. Every fix is a click, not code.
  1. Prepare the sheet (5 min). Create a Google Sheet named Content Engine with two tabs: Queue — columns Date · Pillar · Format · Hook · CTA · UTM link — and Output_Queue — columns Date · Format · Approved post · UTM link · Status. Copy 2–3 rows from your workbook calendar into Queue. Copy the sheet ID from the URL (the long string between /d/ and /edit).
  2. Import. In n8n: Create Workflow → ⋯ (top right) → Import from File → choose Session2_n8n_Agent_Template.json (sent with this pack; or copy the block below into a file saved as .json).
  3. Wire the Trigger. Click Calendar Trigger → Credentials → sign in with Google → paste your sheet ID → pick tab Queue.
  4. Wire the Model. Click OpenAI Chat Model → add your API key. Company blocks OpenAI? Delete that node, add a Gemini or Anthropic chat model node, and drag its dotted line to Draft the Post. The other organs don't change.
  5. Write the Context. Open Draft the Post (Brand Voice) → the system message → replace every [REPLACE] block with your voice, your reader, your rules — use tonight's redlines from Prompt 2.
  6. Claim your seat. Click Approval Gate (Email) → connect Gmail → set sendTo to your own email.
  7. Wire the Queue. Click Ship to Output Queue → same Google credential, same sheet ID, tab Output_Queue.
  8. Run it. Click Execute workflow, then add one new row to Queue. Watch the run travel the canvas. Open your inbox → read the draft → Approve (or Decline — also a win: the gate worked).
  9. Check the memory. Output_Queue now holds your approved post with its UTM link. Log the run in the workbook's Agent_Run_Log.
  10. Export your backup. ⋯ → Download. The JSON is yours forever; the 14-day trial workspace is not. Do this tonight.

Node-by-node: the canvas mapped to the agent anatomy

Node on the canvasOrganWhat it does · what you change
Calendar Trigger
(Google Sheets Trigger)
TriggerPolls your Queue tab hourly; a new row starts a run. The calendar decides what — the agent never picks its own topics. Change: credential + sheet ID.
Draft the Post (Brand Voice)
(AI Agent node)
ContextThe system message is the agent's employment contract: voice, reader, format limits, the no-invented-stats rule, "WHY THIS WORKS". Change: every [REPLACE] block — this is the node you'll edit weekly.
OpenAI Chat Model
(sub-node, dotted line)
ModelThe reasoning engine, plugged into the agent like a bulb. Change: API key — or swap the whole node for Gemini/Claude; the contract stays.
Approval Gate (Email)
(Gmail · Send and Wait)
Approval gateEmails you the draft with Approve/Decline buttons and pauses the run until you click. Never delete this node. Change: sendTo = you.
Approved? (IF node)— the hingeRoutes by your click. Approve → ship; Decline → stop. Change: nothing.
Ship to Output Queue
(Google Sheets append)
Tools + MemoryThe agent's hands (writes to the world) and diary (a growing record of everything you approved). Later upgrade: swap for a real publishing node — after two clean weeks. Change: sheet ID.
Declined — nothing shipsThe success state of a working gate. Change: nothing.
{
  "name": "DigiAIM S2 — First Agent: Calendar → Draft → Approve → Ship",
  "nodes": [
    {
      "id": "a1000000-0000-4000-8000-000000000001",
      "name": "Calendar Trigger",
      "type": "n8n-nodes-base.googleSheetsTrigger",
      "typeVersion": 1,
      "position": [-780, 40],
      "parameters": {
        "event": "rowAdded",
        "pollTimes": {
          "item": [
            {
              "mode": "everyHour"
            }
          ]
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_YOUR_GOOGLE_SHEET_ID"
        },
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Queue"
        }
      },
      "credentials": {
        "googleSheetsTriggerOAuth2Api": {
          "id": "REPLACE_ME",
          "name": "Google Sheets — connect YOUR account here"
        }
      }
    },
    {
      "id": "a1000000-0000-4000-8000-000000000002",
      "name": "Draft the Post (Brand Voice)",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.7,
      "position": [-480, 40],
      "parameters": {
        "promptType": "define",
        "text": "=Calendar row to turn into a post today:\nDate: {{ $json.Date }}\nPillar: {{ $json.Pillar }}\nFormat: {{ $json.Format }}\nHook (use as the opening line, tighten if needed): {{ $json.Hook }}\nCTA: {{ $json.CTA }}\nUTM link (must appear once, unchanged): {{ $json['UTM link'] }}\n\nWrite the complete, ready-to-publish post for this format now.",
        "options": {
          "systemMessage": "You are the content writer for [BRAND NAME], writing in the founder's voice.\n\nVOICE — [REPLACE: 3 lines on your brand voice. Example: Plain Indian English with occasional Hindi phrases. Short sentences. Warm, direct, never salesy. We show real numbers and admit failures.]\n\nAUDIENCE — [REPLACE: who reads this. Example: home cooks aged 25-45 in metro India who distrust packaged masala.]\n\nRULES (non-negotiable):\n1. NEVER invent statistics, customer names, or claims. If the row's hook contains a number, use only that number.\n2. Format limits: Reel caption ≤ 125 words + 5 hashtags. LinkedIn text ≤ 200 words, no hashtags in the first line. Carousel: 6 slide texts of ≤ 20 words each. WhatsApp broadcast ≤ 60 words.\n3. The UTM link appears exactly once, unchanged, where the CTA points.\n4. End every draft with one line starting 'WHY THIS WORKS:' explaining the hook choice in ≤ 15 words. The human approver reads this first.\n5. Output plain text only. No markdown symbols in the post body."
        }
      }
    },
    {
      "id": "a1000000-0000-4000-8000-000000000003",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.2,
      "position": [-500, 260],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {
          "temperature": 0.7
        }
      },
      "credentials": {
        "openAiApi": {
          "id": "REPLACE_ME",
          "name": "OpenAI — paste YOUR API key here"
        }
      }
    },
    {
      "id": "a1000000-0000-4000-8000-000000000004",
      "name": "Approval Gate (Email)",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [-160, 40],
      "parameters": {
        "resource": "message",
        "operation": "sendAndWait",
        "sendTo": "REPLACE_WITH_YOUR_OWN_EMAIL@example.com",
        "subject": "=Approve today's post? — {{ $('Calendar Trigger').item.json.Format }} · {{ $('Calendar Trigger').item.json.Date }}",
        "message": "=The agent drafted this from your calendar. Read it, then decide.\n\n----------------------------------------\n{{ $json.output }}\n----------------------------------------\n\nApprove = it moves to the output queue for posting.\nDecline = nothing ships today. Edit the calendar row and it will retry.\n\nThe rule: automate the shipping, never the judging.",
        "approvalOptions": {
          "values": {
            "approvalType": "double"
          }
        },
        "responseType": "approval",
        "options": {}
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "REPLACE_ME",
          "name": "Gmail — connect YOUR account here"
        }
      }
    },
    {
      "id": "a1000000-0000-4000-8000-000000000005",
      "name": "Approved?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [140, 40],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 2
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c1000000-0000-4000-8000-000000000001",
              "leftValue": "={{ $json.data.approved }}",
              "rightValue": "true",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ]
        },
        "options": {}
      }
    },
    {
      "id": "a1000000-0000-4000-8000-000000000006",
      "name": "Ship to Output Queue",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [440, -80],
      "parameters": {
        "resource": "sheet",
        "operation": "append",
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_YOUR_GOOGLE_SHEET_ID"
        },
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Output_Queue"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Date": "={{ $('Calendar Trigger').item.json.Date }}",
            "Format": "={{ $('Calendar Trigger').item.json.Format }}",
            "Approved post": "={{ $('Draft the Post (Brand Voice)').item.json.output }}",
            "UTM link": "={{ $('Calendar Trigger').item.json['UTM link'] }}",
            "Status": "Approved — ready to post"
          },
          "matchingColumns": [],
          "schema": []
        },
        "options": {}
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "REPLACE_ME",
          "name": "Google Sheets — connect YOUR account here"
        }
      }
    },
    {
      "id": "a1000000-0000-4000-8000-000000000007",
      "name": "Declined — nothing ships",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [440, 160],
      "parameters": {}
    },
    {
      "id": "b1000000-0000-4000-8000-000000000001",
      "name": "Sticky Note — Trigger",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [-860, -180],
      "parameters": {
        "content": "## 1 · TRIGGER (the senses)\nWakes the agent when a new row lands in your calendar sheet. No row, no run — the calendar decides WHAT, the agent only decides HOW to draft it.\n\nSetup: connect your Google account, paste your Sheet ID, point at the tab named 'Queue'.",
        "height": 220,
        "width": 300,
        "color": 4
      }
    },
    {
      "id": "b1000000-0000-4000-8000-000000000002",
      "name": "Sticky Note — Model + Context",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [-540, -180],
      "parameters": {
        "content": "## 2+3 · CONTEXT + MODEL (the brain)\nThe system message is the CONTEXT: your brand voice, audience, and the no-invented-stats rule. The chat model underneath is the MODEL — the reasoning engine. Swap the model without touching the context.\n\nEdit the [REPLACE] blocks before first run.",
        "height": 220,
        "width": 320,
        "color": 5
      }
    },
    {
      "id": "b1000000-0000-4000-8000-000000000003",
      "name": "Sticky Note — Approval",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [-200, -180],
      "parameters": {
        "content": "## 4 · APPROVAL GATE (your judgement)\nsendAndWait: emails you the draft with Approve / Decline buttons and PAUSES until you click. This node is why this is your agent and not your replacement.\n\nNever delete this node. Automate the shipping, not the judging.",
        "height": 220,
        "width": 300,
        "color": 3
      }
    },
    {
      "id": "b1000000-0000-4000-8000-000000000004",
      "name": "Sticky Note — Tools + Memory",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [120, -300],
      "parameters": {
        "content": "## 5+6 · TOOLS + MEMORY (the hands and the diary)\nThe Sheets append node is a TOOL — the agent acting on the world. The Output_Queue tab doubles as MEMORY: a growing record of everything approved, which next week's prompts can read.\n\nUpgrade path: replace the queue with a Buffer/LinkedIn/WhatsApp posting node once you trust the drafts.",
        "height": 240,
        "width": 320,
        "color": 6
      }
    }
  ],
  "connections": {
    "Calendar Trigger": {
      "main": [
        [
          {
            "node": "Draft the Post (Brand Voice)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Draft the Post (Brand Voice)",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Draft the Post (Brand Voice)": {
      "main": [
        [
          {
            "node": "Approval Gate (Email)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approval Gate (Email)": {
      "main": [
        [
          {
            "node": "Approved?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approved?": {
      "main": [
        [
          {
            "node": "Ship to Output Queue",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Declined — nothing ships",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {},
  "meta": {
    "templateCredsSetupCompleted": false
  }
}
Workflow becomes agent: notice which node decides — the model reads the row and chooses how to draft. Everything else is plumbing around one decision and one gate.
Part 3 · 9:15 PM · The judgement loop

Card 6 — The kill-threshold declaration (write it before you automate)

Where: workbook tab Kill_Thresholds — and said out loud to a colleague · Time: 5 min
Declared BEFORE launch. Renegotiating the floor after the numbers arrive is the failure mode.
MY KILL-THRESHOLD DECLARATION — [date]

Format: [e.g., Reels]
The ONE metric that matters: [saves / shares / replies / UTM clicks — intent, not applause]
The floor: [the number below which this format is not working]
The window: [counted in posts, e.g., 4 posts — not in days]
Decision date: [when I read the verdict]
On that date I will write one word: KEEP / KILL / REWORK. There is no fourth option.

Signed (to my own judgement): [name]
One per format you're running. Killing a format on schedule is a win to post in the group — Zomato kills in public; so do we.
Tonight's rule, and this course's rule:
Automate the shipping, never the judging.
DigiAIM · IIM Calcutta · Batch 12 · Session 2 — The Content Engine · Faculty: Siddhesh Joglekar · siddheshj.com
Homework floor: agent approved daily for a week · one Flow/HeyGen video published · 3 posts live with UTM · proof to the batch group.