Skip to content

Composio Client Onboarding — Golden Path

Composio Client Onboarding — Golden Path

Single CLI replaces the ~60-min manual onboarding ritual (one Composio project per client, 8× browser OAuth flows, hand-edit CLAUDE.md tables, hand-edit .mcp.json). Now: ~7 min wall time, 1 click per tool from the client, zero hand-edits.

What the CLI does

  1. Creates a V5 tenant in the gateway (bearer token via POST /admin/tokens/issue).
  2. Initiates a Composio OAuth connected_account for every requested toolkit.
  3. Either emails the client a single landing page with N OAuth links OR prints them to terminal (for screen-share).
  4. Polls every 5s up to 15 min, rendering a live terminal table that flips INITIATED → ACTIVE.
  5. Writes the routing record atomically to ~/.claude/clients/{slug}.json.
  6. Regenerates ~/.claude/clients/index.json + ~/.claude/clients/ROUTING.md.
  7. Prints the summary table + the V5 bearer token (once — store hint only).

Architecture (locked decisions)

  • One canonical Composio project (ascend-canonical) hosting every client. Route per-client via user_id={slug} on every tool call.
  • One shared composio MCP server in .mcp.json pointing at the canonical project.
  • Per-client routing lives in ~/.claude/clients/{slug}.json; CLAUDE.md @-includes the auto-generated ROUTING.md digest.
  • Polling, not webhooks — bounded by the 10-min Composio OAuth window.
  • Bearer tokens print once + last-4 hint stored — never persist raw to disk.
  • SaaS tokens stay in Composio — invariant 5 v3; CLI never writes tokens:* KV keys.

Prereqs

CredentialSource (in lookup order)
COMPOSIO_API_KEY_PRODInfisical project 1c1907fa-... env prod~/.zprofile fallback
ASCEND_ADMIN_KEYInfisical → ~/.zprofile → Wrangler secret list
ASCEND_GATEWAY_TOKEN~/.zprofile (only for --client-email mode; used to call V5 SES)

source ~/.zprofile before invoking. The CLI runs credential discovery in the order above and exits with a clear message if none resolve.

Usage

Terminal window
# Self-service: client gets one email with N OAuth links
npm run onboard:client -- --slug acme --name "Acme" --level developer \
--tools hubspot,salesforce,gong,slack,googlesuper,googleads,linkedin,apollo \
--client-email founder@acme.com
# Assisted: prints OAuth links to terminal for screen-share
npm run onboard:client -- --slug acme --tools hubspot,gong --assist
# Resume a partial onboard (idempotent — skips ACTIVE tools)
npm run onboard:client -- --slug acme --resume
# Add a tool to an existing client
npm run onboard:client -- --slug acme --add-tool quickbooks
# Tear down (test slugs only — confirm via --slug starts with test-*)
npm run onboard:client -- --slug test-acme --teardown
# Dry-run (no API calls, prints intent + validates toolkits resolve)
npm run onboard:client -- --slug acme --tools hubspot --dry-run

Slug rules

  • Lowercase, alphanumeric + hyphen.
  • Regex: ^[a-z0-9][a-z0-9-]{1,30}$
  • Must not already exist in ~/.claude/clients/index.json (the CLI checks).

Exit codes

CodeMeaning
0All tools ACTIVE (or dry-run resolved cleanly)
1Validation error, missing toolkit, OAuth timeout, or any tool FAILED/EXPIRED
2Usage error (missing required flag)

What gets written

~/.claude/clients/
.active ← 1-line file: current client slug
index.json ← {"clients": ["ascend","kahuna","acme"]}
ROUTING.md ← auto-generated digest (CLAUDE.md @-includes this)
ascend.json
kahuna.json
acme.json ← shape: { slug, name, level, v5, composio, tools }

The per-client JSON shape lives in scripts/composio/routing-write.ts::ClientRecord. Atomic write (tmp + rename) — no partial reads from parallel sessions.

Failure modes

  • Toolkit missing in ascend-canonical (e.g. hubspot, salesforce, gong, linkedin_ads as of 2026-05-18). CLI fails loud with auth_config_id lookup error. Resolutions: register the ascend-side OAuth app, or temporarily route that client through kahuna_prod project.
  • OAuth timeout (15 min) — Composio link expired before client clicked. CLI exits 1; re-run with --resume.
  • Composio API 5xx — single attempt, no retry (fail-fast invariant). Re-run with --resume.
  • V5 SES delivery failure (--client-email mode) — CLI exits 1; fall back to --assist and screen-share the links.

Verification (smoke test, throwaway slug)

Terminal window
source ~/.zprofile
npm run onboard:client -- --slug test-acme --name "Test Acme" --level developer \
--tools slack,gamma --assist
# Click each link in the terminal. Wait for "ACTIVE ACTIVE".
cat ~/.claude/clients/test-acme.json # tools.slack.status == "ACTIVE"
grep test-acme ~/.claude/clients/ROUTING.md
curl -H "x-api-key: $COMPOSIO_API_KEY_PROD" \
"https://backend.composio.dev/api/v3/connected_accounts?user_id=test-acme"
# Cleanup:
npm run onboard:client -- --slug test-acme --teardown

Manual-only tools

See docs/composio/manual-tools.md for tools that need out-of-band approval before OAuth works (LinkedIn sandbox, Google Ads dev-token allowlist).

Time-to-onboard

PhaseTodayAfter
V5 tenant3 min30 sec
Composio entitymanual2 sec
Per-tool OAuth8 × 5–10 min = 40–80 min8 × 30 sec client click + parallel polling ≈ 4 min
Routing table5 min manual edit + merge conflict risk0 sec (auto-written)
MCP server setup5 min0 sec (shared server)
Total~60 min~7 min

Client manual effort: 1 click per tool (OAuth consent screen). Nothing else.