Every week you've added one app to your toolbox. Day 7 you sent an email. Day 12 you created a calendar event. Day 17 you read a Sheet range. What would it look like to run all three in a single function?
That's basically what I built with safe_send last time — wrap an action, handle the error, return what I can. Now I chain three of those blocks together. Sheet read feeds the email body, Calendar gets the prep event, Gmail sends the digest.
Exactly the shape. One entry point, three action calls, three results captured. The KPI from the Sheet becomes the body of the email and the context for the QBR prep event. Here's the spine:
sheet_result = toolset.execute_action(Action.GOOGLESHEETS_BATCH_GET,
{"spreadsheet_id": sheet_id, "ranges": ["A1:B2"]})
values = sheet_result.get("valueRanges", [{}])[0].get("values", [])
kpi = values[1][1] if len(values) > 1 and len(values[1]) > 1 else "N/A"So valueRanges[0] is the first range — A1:B2 — and values[1][1] is row 2, column 2. Row 1 is the header, row 2 is the actual KPI number. And if the sheet is empty or the cell is missing, kpi is just "N/A" instead of a crash.
Right. The else "N/A" is your whole error story for the read step — defensive without try/except because a missing cell is not an exception, it's just absent data. Write actions are where you need the guard you built in safe_send:
event = toolset.execute_action(Action.GOOGLECALENDAR_CREATE_EVENT, {
"calendar_id": cal_id, "summary": "QBR Prep",
"start_datetime": "2026-04-21T09:00:00Z",
"end_datetime": "2026-04-21T10:00:00Z",
})
email = toolset.execute_action(Action.GMAIL_SEND_EMAIL, {
"recipient_email": recipient, "subject": "Monday KPI",
"body": f"This week: {kpi}",
})And then the return dict ties everything together — kpi so I can log the value, event_id to confirm the calendar entry was created, email_sent as a bool to know the send went through. I could wire my whole Monday morning in this.
You could — and that's the point. One function call replaces open-Sheet, scan-number, open-Calendar, block-time, compose-email. Before you point recipient at a colleague's inbox, review the safe_send guard: wrap the send, confirm the event, verify the KPI parsed. Tests go to your own address first.
So the pattern is: read → compute → write → write → return a clean summary. Each write step can be wrapped independently if I need fault tolerance. The return dict is the receipt.
That's the professional pattern. Read once, write deliberately, return a structured receipt the caller can log or display. You've just described every production automation that runs reliably past day one.
run_workflow chains three Composio actions into one automated ritual.
| Step | Action | What it does |
|---|---|---|
| 1 | GOOGLESHEETS_BATCH_GET | Reads A1:B2 — header row + one KPI row |
| 2 | GOOGLECALENDAR_CREATE_EVENT | Creates a QBR Prep block on the target calendar |
| 3 | GMAIL_SEND_EMAIL | Sends a one-line KPI digest to the recipient |
valueRanges[0]["values"] is a list of rows; each row is a list of cell strings. values[1][1] is row 2, column 2 — the KPI cell. The else "N/A" guard handles empty sheets without raising.
{"kpi": "...", "event_id": "...", "email_sent": true}All three keys always present — callers can log the KPI value, verify the event was created, and confirm the send succeeded without inspecting raw Composio responses.
Every week you've added one app to your toolbox. Day 7 you sent an email. Day 12 you created a calendar event. Day 17 you read a Sheet range. What would it look like to run all three in a single function?
That's basically what I built with safe_send last time — wrap an action, handle the error, return what I can. Now I chain three of those blocks together. Sheet read feeds the email body, Calendar gets the prep event, Gmail sends the digest.
Exactly the shape. One entry point, three action calls, three results captured. The KPI from the Sheet becomes the body of the email and the context for the QBR prep event. Here's the spine:
sheet_result = toolset.execute_action(Action.GOOGLESHEETS_BATCH_GET,
{"spreadsheet_id": sheet_id, "ranges": ["A1:B2"]})
values = sheet_result.get("valueRanges", [{}])[0].get("values", [])
kpi = values[1][1] if len(values) > 1 and len(values[1]) > 1 else "N/A"So valueRanges[0] is the first range — A1:B2 — and values[1][1] is row 2, column 2. Row 1 is the header, row 2 is the actual KPI number. And if the sheet is empty or the cell is missing, kpi is just "N/A" instead of a crash.
Right. The else "N/A" is your whole error story for the read step — defensive without try/except because a missing cell is not an exception, it's just absent data. Write actions are where you need the guard you built in safe_send:
event = toolset.execute_action(Action.GOOGLECALENDAR_CREATE_EVENT, {
"calendar_id": cal_id, "summary": "QBR Prep",
"start_datetime": "2026-04-21T09:00:00Z",
"end_datetime": "2026-04-21T10:00:00Z",
})
email = toolset.execute_action(Action.GMAIL_SEND_EMAIL, {
"recipient_email": recipient, "subject": "Monday KPI",
"body": f"This week: {kpi}",
})And then the return dict ties everything together — kpi so I can log the value, event_id to confirm the calendar entry was created, email_sent as a bool to know the send went through. I could wire my whole Monday morning in this.
You could — and that's the point. One function call replaces open-Sheet, scan-number, open-Calendar, block-time, compose-email. Before you point recipient at a colleague's inbox, review the safe_send guard: wrap the send, confirm the event, verify the KPI parsed. Tests go to your own address first.
So the pattern is: read → compute → write → write → return a clean summary. Each write step can be wrapped independently if I need fault tolerance. The return dict is the receipt.
That's the professional pattern. Read once, write deliberately, return a structured receipt the caller can log or display. You've just described every production automation that runs reliably past day one.
run_workflow chains three Composio actions into one automated ritual.
| Step | Action | What it does |
|---|---|---|
| 1 | GOOGLESHEETS_BATCH_GET | Reads A1:B2 — header row + one KPI row |
| 2 | GOOGLECALENDAR_CREATE_EVENT | Creates a QBR Prep block on the target calendar |
| 3 | GMAIL_SEND_EMAIL | Sends a one-line KPI digest to the recipient |
valueRanges[0]["values"] is a list of rows; each row is a list of cell strings. values[1][1] is row 2, column 2 — the KPI cell. The else "N/A" guard handles empty sheets without raising.
{"kpi": "...", "event_id": "...", "email_sent": true}All three keys always present — callers can log the KPI value, verify the event was created, and confirm the send succeeded without inspecting raw Composio responses.
Create a free account to get started. Paid plans unlock all tracks.