You've been writing pure-Python code that runs in your browser. From today the code you write reaches out of the sandbox to real APIs — your Gmail, your Sheets, your Slack. The primitive is a single function call.
How does Python know which Gmail account to talk to?
It doesn't, until it's been told. When you connected Gmail in onboarding, the platform stored an OAuth credential under your account. The lesson runtime injects two things into your script's scope: toolset (the Composio client, already authenticated for you) and Action (an enum of all the tool slugs). You don't pip install anything; the runtime gives them to you because you're on a pro-tier track with the right connections.
result = toolset.execute_action(Action.GMAIL_FETCH_EMAILS, {"max_results": 1})
print(type(result))Action.GMAIL_FETCH_EMAILS looks like a constant. What's the underlying string?
"GMAIL_FETCH_EMAILS" — Composio's name for that tool. The enum is just a typo-safe wrapper. Action.GMAIL_FETCH_EMAILS and the literal string "GMAIL_FETCH_EMAILS" produce the same call — the enum is preferred because your editor can autocomplete and Python catches typos at parse time.
And execute_action returns what?
A dict. Its shape depends on the tool, but it's always a Python dict with string keys. Today's exercise is just to make the call and confirm the type — <class 'dict'>.
Every interaction with an external service follows the same shape:
result = toolset.execute_action(Action.<TOOL_SLUG>, { ...args... })Three pieces:
toolset — the Composio client, injected by the runtime, already authenticated for your Gmail/Slack/Sheets accounts.Action.<TOOL_SLUG> — the tool to call. Composio names them in SCREAMING_SNAKE_CASE: GMAIL_FETCH_EMAILS, GMAIL_SEND_EMAIL, SLACK_SEND_MESSAGE, GOOGLESHEETS_BATCH_GET, etc. The enum exists so your editor can autocomplete and catch typos.{} if no args needed.| In your scope | Source |
|---|---|
toolset | runtime injection |
Action enum | runtime injection |
Standard Python (print, len, for, dict, ...) | Python itself |
| Your account's OAuth credentials | Composio (zero-touch — used by toolset under the hood) |
What isn't in scope: the underlying Composio Python SDK class, the proxy URL, your access tokens. The runtime hides those. You only see the friendly two-symbol surface.
result = toolset.execute_action(Action.GMAIL_FETCH_EMAILS, {"max_results": 1})
# result is a dict — shape varies by tool, but it's always JSON-serialisable Python
# {'messages': [{...}], 'next_page_token': '...', ...}For Gmail's FETCH_EMAILS, the dict has a messages key holding a list. For SLACK_SEND_MESSAGE, the dict echoes back the posted message's metadata. The exact shape is documented per-tool — when in doubt, print(result) once and read the structure.
Why not gmail.list_messages(limit=1) directly? The honest answer: Composio's design. They support 200+ tools through one uniform execute_action(slug, args) shape, which keeps the platform's API surface tiny. The trade-off is slight verbosity. You'll get used to it within three lessons.
You've been writing pure-Python code that runs in your browser. From today the code you write reaches out of the sandbox to real APIs — your Gmail, your Sheets, your Slack. The primitive is a single function call.
How does Python know which Gmail account to talk to?
It doesn't, until it's been told. When you connected Gmail in onboarding, the platform stored an OAuth credential under your account. The lesson runtime injects two things into your script's scope: toolset (the Composio client, already authenticated for you) and Action (an enum of all the tool slugs). You don't pip install anything; the runtime gives them to you because you're on a pro-tier track with the right connections.
result = toolset.execute_action(Action.GMAIL_FETCH_EMAILS, {"max_results": 1})
print(type(result))Action.GMAIL_FETCH_EMAILS looks like a constant. What's the underlying string?
"GMAIL_FETCH_EMAILS" — Composio's name for that tool. The enum is just a typo-safe wrapper. Action.GMAIL_FETCH_EMAILS and the literal string "GMAIL_FETCH_EMAILS" produce the same call — the enum is preferred because your editor can autocomplete and Python catches typos at parse time.
And execute_action returns what?
A dict. Its shape depends on the tool, but it's always a Python dict with string keys. Today's exercise is just to make the call and confirm the type — <class 'dict'>.
Every interaction with an external service follows the same shape:
result = toolset.execute_action(Action.<TOOL_SLUG>, { ...args... })Three pieces:
toolset — the Composio client, injected by the runtime, already authenticated for your Gmail/Slack/Sheets accounts.Action.<TOOL_SLUG> — the tool to call. Composio names them in SCREAMING_SNAKE_CASE: GMAIL_FETCH_EMAILS, GMAIL_SEND_EMAIL, SLACK_SEND_MESSAGE, GOOGLESHEETS_BATCH_GET, etc. The enum exists so your editor can autocomplete and catch typos.{} if no args needed.| In your scope | Source |
|---|---|
toolset | runtime injection |
Action enum | runtime injection |
Standard Python (print, len, for, dict, ...) | Python itself |
| Your account's OAuth credentials | Composio (zero-touch — used by toolset under the hood) |
What isn't in scope: the underlying Composio Python SDK class, the proxy URL, your access tokens. The runtime hides those. You only see the friendly two-symbol surface.
result = toolset.execute_action(Action.GMAIL_FETCH_EMAILS, {"max_results": 1})
# result is a dict — shape varies by tool, but it's always JSON-serialisable Python
# {'messages': [{...}], 'next_page_token': '...', ...}For Gmail's FETCH_EMAILS, the dict has a messages key holding a list. For SLACK_SEND_MESSAGE, the dict echoes back the posted message's metadata. The exact shape is documented per-tool — when in doubt, print(result) once and read the structure.
Why not gmail.list_messages(limit=1) directly? The honest answer: Composio's design. They support 200+ tools through one uniform execute_action(slug, args) shape, which keeps the platform's API surface tiny. The trade-off is slight verbosity. You'll get used to it within three lessons.
Create a free account to get started. Paid plans unlock all tracks.