Skip to main content
ClaudeWave
Skill873 repo starsupdated today

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.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/desplega-ai/agent-swarm /tmp/composio && cp -r /tmp/composio/templates/skills/composio ~/.claude/skills/composio
Then start a new Claude Code session; the skill loads automatically.

SKILL.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
   them