You have read_range, safe_send, create_event — all the pieces. What does your Monday ops workflow look like when they chain together?
I could wire my whole Monday morning in this. Read yesterday's new customers from the Sheet, send each one a welcome email to myself for review, and create a 48-hour check-in event for the top-plan ones. That's three hours back, every week.
That's the capstone. run_workflow(sheet_id, cal_id, self_email) — read the Sheet, draft a welcome email per customer, create a Calendar check-in for top-plan customers. Sent to self_email for safety:
rows = read_range(sheet_id, "Sheet1!A:D")
for row in rows[1:]:
name, plan, mrr, status = row[0], row[1], float(row[2]), row[3]
body = f"Welcome {name}! Your {plan} plan is active."
safe_send(self_email, f"Welcome: {name}", body)
if plan.lower() in ["pro", "enterprise"]:
create_event(cal_id, f"48h check-in: {name}", start, end)Why send the welcome emails to self_email instead of the customer directly?
Safety. You're verifying the pipeline works before it touches real customers. After three successful runs to your own inbox, you update the recipient logic to use the customer's email column. Here's the full function:
def run_workflow(sheet_id: str, cal_id: str, self_email: str) -> dict:
rows = toolset.execute_action(Action.GOOGLESHEETS_BATCH_GET, {"spreadsheet_id": sheet_id, "ranges": ["Sheet1!A:D"]}).get("valueRanges", [{}])[0].get("values", [])
emails_sent = 0
events_created = 0
for row in rows[1:]:
if len(row) < 4:
continue
name, plan, mrr_str, status = row[0], row[1], row[2], row[3]
body = f"Welcome {name}! Your {plan} plan is now active."
send_result = safe_send(self_email, f"Welcome: {name}", body)
if send_result.get("status") != "auth_required":
emails_sent += 1
if plan.lower() in ["pro", "enterprise"]:
toolset.execute_action(Action.GOOGLECALENDAR_CREATE_EVENT, {"calendar_id": cal_id, "summary": f"48h check-in: {name}", "start": {"dateTime": "2026-04-22T10:00:00Z"}, "end": {"dateTime": "2026-04-22T10:30:00Z"}})
events_created += 1
result = {"emails_drafted": emails_sent, "events_created": events_created}
print(f"Workflow complete: {result}")
return resultI ran this on last week's real customer rows. Two welcome emails in my inbox, one calendar check-in event. Three hours of manual ops, done in 10 seconds.
Three hours a week. 150 hours a year. That's a meaningful chunk of founder time reclaimed.
Four weeks. From 'what is a Composio action' to 'I have a three-app workflow that runs my Monday ops.' That's real leverage.
The capstone is a starting point, not an endpoint. Once it's stable, extend it: add email column to the Sheet, update safe_send to use the customer's real address, add a LinkedIn post for every new Pro customer. The scaffold is solid.
run_workflow is a three-app chain that replaces your entire Monday new-customer ops ritual:
GOOGLESHEETS_BATCH_GET → read new customer rowssafe_send → draft welcome email per customer (to self for safety)GOOGLECALENDAR_CREATE_EVENT → 48h check-in for pro/enterprise customers{"emails_drafted": N, "events_created": M}Always send to self_email during testing. Extend to real customer emails after three successful runs.
Check len(row) >= 4 before unpacking. Sheets rows can have fewer columns than expected.
You have read_range, safe_send, create_event — all the pieces. What does your Monday ops workflow look like when they chain together?
I could wire my whole Monday morning in this. Read yesterday's new customers from the Sheet, send each one a welcome email to myself for review, and create a 48-hour check-in event for the top-plan ones. That's three hours back, every week.
That's the capstone. run_workflow(sheet_id, cal_id, self_email) — read the Sheet, draft a welcome email per customer, create a Calendar check-in for top-plan customers. Sent to self_email for safety:
rows = read_range(sheet_id, "Sheet1!A:D")
for row in rows[1:]:
name, plan, mrr, status = row[0], row[1], float(row[2]), row[3]
body = f"Welcome {name}! Your {plan} plan is active."
safe_send(self_email, f"Welcome: {name}", body)
if plan.lower() in ["pro", "enterprise"]:
create_event(cal_id, f"48h check-in: {name}", start, end)Why send the welcome emails to self_email instead of the customer directly?
Safety. You're verifying the pipeline works before it touches real customers. After three successful runs to your own inbox, you update the recipient logic to use the customer's email column. Here's the full function:
def run_workflow(sheet_id: str, cal_id: str, self_email: str) -> dict:
rows = toolset.execute_action(Action.GOOGLESHEETS_BATCH_GET, {"spreadsheet_id": sheet_id, "ranges": ["Sheet1!A:D"]}).get("valueRanges", [{}])[0].get("values", [])
emails_sent = 0
events_created = 0
for row in rows[1:]:
if len(row) < 4:
continue
name, plan, mrr_str, status = row[0], row[1], row[2], row[3]
body = f"Welcome {name}! Your {plan} plan is now active."
send_result = safe_send(self_email, f"Welcome: {name}", body)
if send_result.get("status") != "auth_required":
emails_sent += 1
if plan.lower() in ["pro", "enterprise"]:
toolset.execute_action(Action.GOOGLECALENDAR_CREATE_EVENT, {"calendar_id": cal_id, "summary": f"48h check-in: {name}", "start": {"dateTime": "2026-04-22T10:00:00Z"}, "end": {"dateTime": "2026-04-22T10:30:00Z"}})
events_created += 1
result = {"emails_drafted": emails_sent, "events_created": events_created}
print(f"Workflow complete: {result}")
return resultI ran this on last week's real customer rows. Two welcome emails in my inbox, one calendar check-in event. Three hours of manual ops, done in 10 seconds.
Three hours a week. 150 hours a year. That's a meaningful chunk of founder time reclaimed.
Four weeks. From 'what is a Composio action' to 'I have a three-app workflow that runs my Monday ops.' That's real leverage.
The capstone is a starting point, not an endpoint. Once it's stable, extend it: add email column to the Sheet, update safe_send to use the customer's real address, add a LinkedIn post for every new Pro customer. The scaffold is solid.
run_workflow is a three-app chain that replaces your entire Monday new-customer ops ritual:
GOOGLESHEETS_BATCH_GET → read new customer rowssafe_send → draft welcome email per customer (to self for safety)GOOGLECALENDAR_CREATE_EVENT → 48h check-in for pro/enterprise customers{"emails_drafted": N, "events_created": M}Always send to self_email during testing. Extend to real customer emails after three successful runs.
Check len(row) >= 4 before unpacking. Sheets rows can have fewer columns than expected.
Create a free account to get started. Paid plans unlock all tracks.