You wrap every project with a case-study post on LinkedIn. You mean to write it but never do — the project is done, the invoice is sent, the moment is gone. What if the post wrote itself from the project doc?
read_doc returns the doc content. Extract the first 300 characters of body text and pass it to LINKEDIN_CREATE_LINKED_IN_POST.
Exactly. The first meaningful paragraph of a proposal doc is usually enough for a project wrap post. LinkedIn accepts plain text; extract it from the nested Docs body structure and pass it through. The chain: Docs → LinkedIn, two actions, one function:
result = toolset.execute_action(
Action.GOOGLEDOCS_GET_DOCUMENT_BY_ID,
{"document_id": doc_id}
)
# extract text from body structure
body_content = result.get("body", {}).get("content", [])
text = ""
for elem in body_content:
for run in elem.get("paragraph", {}).get("elements", []):
text += run.get("textRun", {}).get("content", "")
snippet = text[:300].strip()That nested structure for extracting text — is there a simpler way?
The Composio wrapper may surface a simpler body_text field in the response — check the actual response in your first run. The nested extraction above handles the raw Google Docs API shape. Either way, the LinkedIn call is the same: pass the text to LINKEDIN_CREATE_LINKED_IN_POST.
So after a project wraps I call doc_to_post with the proposal doc ID and the case-study post appears on LinkedIn. Automatically.
The post you meant to write every time a project wrapped. Now it writes itself:
def doc_to_post(doc_id: str) -> dict:
doc = read_doc(doc_id)
title = doc.get("title", "")
# try to get a text snippet from the doc
body_text = doc.get("body_text", doc.get("body", {}).get("content", ""))
snippet = str(body_text)[:300].strip() if body_text else title
post_text = f"Project complete: {title}\n\n{snippet}" if snippet else f"Project complete: {title}"
result = toolset.execute_action(
Action.LINKEDIN_CREATE_LINKED_IN_POST,
{"text": post_text}
)
print(f"LinkedIn post created")
return resultThree years of missed case-study posts. One function to fix that.
Always review the post text before publishing to a real audience. Test with read_doc first to inspect the body content shape for your specific docs.
Read the doc, take the first 300 characters of body text, post it to LinkedIn:
doc = read_doc(doc_id)
snippet = doc.get('body', '')[:300]
result = toolset.execute_action(
action=Action.LINKEDIN_CREATE_LINKED_IN_POST,
params={'text': snippet}
)LinkedIn preview text is typically 300 characters before a 'See more' truncation. Using the first 300 characters of the project wrap-up doc gives a natural teaser that invites clicks.
LinkedIn is a write destination. This is the first lesson in the track to post to a public-facing platform — always test the snippet content manually before automating. You cannot un-post a LinkedIn update from code.
You wrap every project with a case-study post on LinkedIn. You mean to write it but never do — the project is done, the invoice is sent, the moment is gone. What if the post wrote itself from the project doc?
read_doc returns the doc content. Extract the first 300 characters of body text and pass it to LINKEDIN_CREATE_LINKED_IN_POST.
Exactly. The first meaningful paragraph of a proposal doc is usually enough for a project wrap post. LinkedIn accepts plain text; extract it from the nested Docs body structure and pass it through. The chain: Docs → LinkedIn, two actions, one function:
result = toolset.execute_action(
Action.GOOGLEDOCS_GET_DOCUMENT_BY_ID,
{"document_id": doc_id}
)
# extract text from body structure
body_content = result.get("body", {}).get("content", [])
text = ""
for elem in body_content:
for run in elem.get("paragraph", {}).get("elements", []):
text += run.get("textRun", {}).get("content", "")
snippet = text[:300].strip()That nested structure for extracting text — is there a simpler way?
The Composio wrapper may surface a simpler body_text field in the response — check the actual response in your first run. The nested extraction above handles the raw Google Docs API shape. Either way, the LinkedIn call is the same: pass the text to LINKEDIN_CREATE_LINKED_IN_POST.
So after a project wraps I call doc_to_post with the proposal doc ID and the case-study post appears on LinkedIn. Automatically.
The post you meant to write every time a project wrapped. Now it writes itself:
def doc_to_post(doc_id: str) -> dict:
doc = read_doc(doc_id)
title = doc.get("title", "")
# try to get a text snippet from the doc
body_text = doc.get("body_text", doc.get("body", {}).get("content", ""))
snippet = str(body_text)[:300].strip() if body_text else title
post_text = f"Project complete: {title}\n\n{snippet}" if snippet else f"Project complete: {title}"
result = toolset.execute_action(
Action.LINKEDIN_CREATE_LINKED_IN_POST,
{"text": post_text}
)
print(f"LinkedIn post created")
return resultThree years of missed case-study posts. One function to fix that.
Always review the post text before publishing to a real audience. Test with read_doc first to inspect the body content shape for your specific docs.
Read the doc, take the first 300 characters of body text, post it to LinkedIn:
doc = read_doc(doc_id)
snippet = doc.get('body', '')[:300]
result = toolset.execute_action(
action=Action.LINKEDIN_CREATE_LINKED_IN_POST,
params={'text': snippet}
)LinkedIn preview text is typically 300 characters before a 'See more' truncation. Using the first 300 characters of the project wrap-up doc gives a natural teaser that invites clicks.
LinkedIn is a write destination. This is the first lesson in the track to post to a public-facing platform — always test the snippet content manually before automating. You cannot un-post a LinkedIn update from code.
Create a free account to get started. Paid plans unlock all tracks.