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.
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
| C | Context | Who you are, whom you serve, your positioning from Session 1, the goal action. |
| R | Role | The expert hat the AI wears (social strategist, shot director, speechwriter). |
| I | Instructions | The task, sequenced — with STOP points where your approval gates the next step. |
| S | Specifics | Formats, counts, word limits, UTM links, the 8–12 concept rule. |
| P | Pain points | What 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
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
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
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
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)
- Prepare the sheet (5 min). Create a Google Sheet named
Content Enginewith two tabs:Queue— columnsDate · Pillar · Format · Hook · CTA · UTM link— andOutput_Queue— columnsDate · Format · Approved post · UTM link · Status. Copy 2–3 rows from your workbook calendar intoQueue. Copy the sheet ID from the URL (the long string between/d/and/edit). - 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). - Wire the Trigger. Click Calendar Trigger → Credentials → sign in with Google → paste your sheet ID → pick tab
Queue. - 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.
- 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. - Claim your seat. Click Approval Gate (Email) → connect Gmail → set sendTo to your own email.
- Wire the Queue. Click Ship to Output Queue → same Google credential, same sheet ID, tab
Output_Queue. - 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). - Check the memory.
Output_Queuenow holds your approved post with its UTM link. Log the run in the workbook'sAgent_Run_Log. - 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 canvas | Organ | What it does · what you change |
|---|---|---|
| Calendar Trigger (Google Sheets Trigger) | Trigger | Polls 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) | Context | The 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) | Model | The 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 gate | Emails 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 hinge | Routes by your click. Approve → ship; Decline → stop. Change: nothing. |
| Ship to Output Queue (Google Sheets append) | Tools + Memory | The 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 ships | — | The 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)
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.