composio
Composio is a hub skill that connects Agent Swarm agents to third-party applications like Gmail, GitHub, Slack, Notion, and HubSpot through Composio's Tool Router or direct execute endpoints. Use it when tasks require accessing external app tools, either through multi-turn Tool Router sessions for agent conversations or direct execute calls for one-off operations, with user identification via email and explicit connected account pinning for reliability.
git clone --depth 1 https://github.com/desplega-ai/agent-swarm /tmp/composio && cp -r /tmp/composio/templates/skills/composio ~/.claude/skills/composioSKILL.md
# Composio
Hub skill for Composio-managed third-party app access from the swarm. Three call
surfaces are available when the deployment has enabled them:
- CLI: `agent-swarm x composio <METHOD> <path> [--body '<json>']`
- MCP: `swarm_x` with `target: "composio"`
- Script connection: `ctx.api.composio.<operationId>(args)` inside a swarm script
`COMPOSIO_API_KEY` is deployment-scoped and injected by the CLI/API process — you
never pass or see it. All paths are **relative** Composio REST paths.
> **Per-app playbooks (verified slugs + argument shapes + gotchas):**
> [[composio-gmail]] · [[composio-google-calendar]] · [[composio-google-docs]].
> Read the sibling skill for the app you're touching — it lists the verified tool
> slugs so you don't have to `/search` blind.
## Core Model
- **`user_id`** is the app user whose connected accounts are used. A deployment
commonly uses the person's **email** as `user_id` (for example,
`<connected-account-email>`). Resolve it with the procedure below. There is **no explicit
"create user" call** — a user is created implicitly the first time you reference
its `user_id` (e.g. when you create a Connect Link). Don't look for a
`POST /users` endpoint; it doesn't exist in this flow.
- **Auth config** (`ac_…`) = a project-level OAuth app config (one per toolkit,
set up in the Composio dashboard). A project can have several.
- **Connected account** (`ca_…`) = a specific user's authorized connection to a
toolkit. Persists across sessions under that `user_id`.
- **Connect Link** = the short-lived URL the user clicks to authorize OAuth.
- **Tool Router session** = a task/conversation runtime context that auto-resolves
the right connected account for a toolkit set. Reuse its `session_id`; create a
new one if the user, toolkit set, auth config, or pinned account changes.
## Resolve the user and connected account
Do this before substituting any `user_id` or `connected_account_id` placeholder:
1. Read the current task details and take its `requestedByUserId`.
2. Call `resolve-user` with `userId: "<requestedByUserId>"`. Inspect the returned
`externalIds` for `kind: "composio"`; that entry's `externalId` is the
Composio `user_id`.
3. List connected accounts filtered by that resolved value:
`GET /connected_accounts?user_id=<resolved-composio-user-id>`. Select the
requested toolkit's `ACTIVE` row and use its `id` as
`connected_account_id`.
4. If the task has no requester, the requester has no Composio identity, or the
filtered result is ambiguous, run `GET /connected_accounts` without a filter
and compare the returned toolkit and user identity fields. If more than one
account is still plausible, ask which identity/account to use. Never guess
from another task's example.
After selecting an account, prove it with a harmless real read; `ACTIVE` status
alone does not prove that its token works.
## Two ways to call a tool — and when to use each
1. **Tool Router session** (`/tool_router/session…`) — best for multi-turn agent
work over a toolkit set. Auto-resolves connections, supports in-session
`/search`. **But** it can fail with `ToolRouterV2_NoActiveConnection` (code
4302) when stale/duplicate accounts shadow the good one (see Gotchas).
2. **Direct execute** (`POST /tools/execute/<TOOL_SLUG>`) — best for one-off reads,
verification, or when the session reports no active connection. Pin the account
explicitly with `connected_account_id`. **This is the reliable path** when a
user has exactly one good connection per toolkit.
```bash
agent-swarm x composio POST /tools/execute/GMAIL_FETCH_EMAILS \
--body '{"user_id":"<connected-account-email>","connected_account_id":"<active-connected-account-id>","arguments":{"max_results":3,"include_payload":false,"verbose":false}}'
```
Resolve both placeholders through **Resolve the user and connected account**
above.
## Script connection surface
`ctx.api.composio` exists only when an enabled script connection with slug
`composio` is registered for the calling agent, repository, or globally. Inspect
`Object.keys(ctx.api ?? {})` before assuming it is present. Use the script
connection listing's generated types or `script-query-types` to discover current
operation IDs and parameter shapes.
```ts
import type { ScriptContext } from "swarm-sdk";
export default async function (args: { userId: string }, ctx: ScriptContext) {
if (!ctx.api?.composio) throw new Error("The composio script connection is not available");
return ctx.api.composio.getV31ConnectedAccounts({
query: { user_ids: [args.userId] },
});
}
```
Generated OpenAPI operations accept only the applicable top-level containers:
`path`, `query`, `header`, and `body`. Put each argument under the container
declared by the generated type. Unknown top-level keys now fail loudly and often
include a nesting hint; fix the call instead of retrying it unchanged.
## Recipe A — Register a user + send Connect Links (one per toolkit)
1. **List the project's auth configs** to get the `ac_…` ids:
```bash
agent-swarm x composio GET "/auth_configs" \
| jq -r '.items[] | "\(.toolkit.slug)\t\(.id)\t\(.name)"'
```
2. **Create one Connect Link per auth config** (flat payload — the user is created
implicitly here):
```bash
agent-swarm x composio POST /connected_accounts/link \
--body '{"auth_config_id":"<auth-config-id>","user_id":"<connected-account-email>"}'
# → returns { redirect_url / connect_url: "https://connect.composio.dev/link/lk_…" }
```
- **Use `/connected_accounts/link`, NOT `POST /connected_accounts`.** The older
path now returns 400 for Composio-managed OAuth configs.
- **There is no single bundled URL** for multiple toolkits — Composio issues
**one link per toolkit**. Send all of them, labelled per app.
3. **Links expire ~10 minutes** after creation (link-start token TTL).
**Regenerate fresh links immediately before posting** to the user, and tell
themCode search agent for exploring any codebase. Use for finding code by intent, locating implementations, understanding how something works, or discovering related code. Prefer over Grep/Glob/Read for any semantic or exploratory question.
Guide for running local E2E tests with API server, Docker lead/worker containers, task creation, log verification, UI dashboard, and cleanup
Close a GitHub or GitLab issue with a summary comment
Create a pull request (GitHub) or merge request (GitLab) from the current branch
Implement a GitHub issue or GitLab issue and create a PR/MR
Investigate and triage a Sentry error issue
Respond to a GitHub issue/PR or GitLab issue/MR
Review a task that has been offered to you and decide whether to accept or reject it