upcoming_to_tasks turned calendar events into Google Tasks — two apps, one function, no copy-pasting. Today we cross a line. LinkedIn is a public network. Once a post goes out, it's live. What changes when the output isn't a row in a spreadsheet but a message your entire network can see?
With upcoming_to_tasks I could always delete a bad task quietly. A LinkedIn post is different — I can't un-publish it without someone already seeing it. I'd want to be sure the content is right before calling the action.
Exactly. Treat every write-to-public-network action the same way you treat GMAIL_SEND_EMAIL: draft, review, then publish. In production you'd confirm the text first. In this lesson we keep it safe — doc_to_post pulls the doc title and wraps it in a short "Just published: {title}" format. Short, factual, recoverable if needed:
doc = toolset.execute_action(Action.GOOGLEDOCS_GET_DOCUMENT_BY_ID, {"id": doc_id})
title = doc.get("title", "Untitled Post")
post = toolset.execute_action(Action.LINKEDIN_CREATE_LINKED_IN_POST, {
"commentary": f"Just published: {title}",
})The Google Docs action returns a title key directly? I expected something nested like body.content.
Composio surfaces the doc's metadata at the top level of the response — title is a first-class field, not buried in content. The full body is in body.content if you need it later, but for a post summary the title alone is enough. No parsing, no recursion:
def doc_to_post(doc_id: str) -> dict:
doc = toolset.execute_action(Action.GOOGLEDOCS_GET_DOCUMENT_BY_ID, {"id": doc_id})
title = doc.get("title", "Untitled Post")
post = toolset.execute_action(Action.LINKEDIN_CREATE_LINKED_IN_POST, {
"commentary": f"Just published: {title}",
})
print(f"Posted to LinkedIn: {title}")
return postI finish writing a strategy memo in Google Docs, run one function, and it's on LinkedIn. I could wire this into the Monday morning pipeline — doc ready by Sunday night, post fires Monday at nine.
One caution before you schedule it: LinkedIn posts are public and immediate. Always preview the commentary string before calling the action in production — show it to yourself in a dry run, confirm it reads well, then publish. The function itself has no undo.
So the safe pattern is: run it once manually, check what it posts, then automate. Same discipline I used with send_email in Week 1.
Exactly the same discipline. You've now applied it across Gmail, Calendar, Tasks, Sheets, Docs, and LinkedIn. That's six apps, one mental model.
TL;DR: GOOGLEDOCS_GET_DOCUMENT_BY_ID returns doc metadata including title. LINKEDIN_CREATE_LINKED_IN_POST accepts a commentary string and publishes immediately.
| Action | Key used | Default |
|---|---|---|
GOOGLEDOCS_GET_DOCUMENT_BY_ID | title | "Untitled Post" |
LINKEDIN_CREATE_LINKED_IN_POST | (full response returned) | — |
LinkedIn posts are public and immediate. In any real workflow: generate the text, show it to the user for approval, then call LINKEDIN_CREATE_LINKED_IN_POST. Tests use a real account — keep commentary short and factual.
upcoming_to_tasks turned calendar events into Google Tasks — two apps, one function, no copy-pasting. Today we cross a line. LinkedIn is a public network. Once a post goes out, it's live. What changes when the output isn't a row in a spreadsheet but a message your entire network can see?
With upcoming_to_tasks I could always delete a bad task quietly. A LinkedIn post is different — I can't un-publish it without someone already seeing it. I'd want to be sure the content is right before calling the action.
Exactly. Treat every write-to-public-network action the same way you treat GMAIL_SEND_EMAIL: draft, review, then publish. In production you'd confirm the text first. In this lesson we keep it safe — doc_to_post pulls the doc title and wraps it in a short "Just published: {title}" format. Short, factual, recoverable if needed:
doc = toolset.execute_action(Action.GOOGLEDOCS_GET_DOCUMENT_BY_ID, {"id": doc_id})
title = doc.get("title", "Untitled Post")
post = toolset.execute_action(Action.LINKEDIN_CREATE_LINKED_IN_POST, {
"commentary": f"Just published: {title}",
})The Google Docs action returns a title key directly? I expected something nested like body.content.
Composio surfaces the doc's metadata at the top level of the response — title is a first-class field, not buried in content. The full body is in body.content if you need it later, but for a post summary the title alone is enough. No parsing, no recursion:
def doc_to_post(doc_id: str) -> dict:
doc = toolset.execute_action(Action.GOOGLEDOCS_GET_DOCUMENT_BY_ID, {"id": doc_id})
title = doc.get("title", "Untitled Post")
post = toolset.execute_action(Action.LINKEDIN_CREATE_LINKED_IN_POST, {
"commentary": f"Just published: {title}",
})
print(f"Posted to LinkedIn: {title}")
return postI finish writing a strategy memo in Google Docs, run one function, and it's on LinkedIn. I could wire this into the Monday morning pipeline — doc ready by Sunday night, post fires Monday at nine.
One caution before you schedule it: LinkedIn posts are public and immediate. Always preview the commentary string before calling the action in production — show it to yourself in a dry run, confirm it reads well, then publish. The function itself has no undo.
So the safe pattern is: run it once manually, check what it posts, then automate. Same discipline I used with send_email in Week 1.
Exactly the same discipline. You've now applied it across Gmail, Calendar, Tasks, Sheets, Docs, and LinkedIn. That's six apps, one mental model.
TL;DR: GOOGLEDOCS_GET_DOCUMENT_BY_ID returns doc metadata including title. LINKEDIN_CREATE_LINKED_IN_POST accepts a commentary string and publishes immediately.
| Action | Key used | Default |
|---|---|---|
GOOGLEDOCS_GET_DOCUMENT_BY_ID | title | "Untitled Post" |
LINKEDIN_CREATE_LINKED_IN_POST | (full response returned) | — |
LinkedIn posts are public and immediate. In any real workflow: generate the text, show it to the user for approval, then call LINKEDIN_CREATE_LINKED_IN_POST. Tests use a real account — keep commentary short and factual.
Create a free account to get started. Paid plans unlock all tracks.