14 KiB
AGENTS.md
Instructions for AI agents working on @composio/cli. The sibling CLAUDE.md is a symlink to this file.
Required Checks
When you touch CLI code (anything under ts/packages/cli/src/), run pnpm typecheck from the repo root before pushing. Fix all type errors. Build/lint failures block CI.
Architecture
The CLI is built on the Effect.ts ecosystem and runs on Bun. Service-oriented architecture with dependency injection via Effect layers, generator-based control flow (Effect.gen), and structured error handling.
Entry Point — src/bin.ts
Bootstraps the CLI by composing Effect layers and running the root command via BunRuntime.runMain():
CliConfigLive— @effect/cli behavior (case-sensitive, no auto-correct, no built-ins)ComposioUserContextLive— User authentication state from~/.composio/ComposioSessionRepositoryLive— OAuth2 session managementComposioToolkitsRepositoryCachedLive— Cached API client for toolkits/toolsUpgradeBinaryLive— Self-update from GitHub releasesBunFileSystem.layer,BunContext.layer— Bun runtime integration
Errors are captured via the custom effect-errors/ module (source-mapped stack traces, Effect span timelines, formatted output).
Commands — src/commands/
Each command uses @effect/cli's Command.make() pattern. Top-level command files end in .cmd.ts; nested command groups live in their own subdirectory with a <group>.cmd.ts entry. Current top-level commands:
| Group / Command | Purpose | |
|---|---|---|
version |
Display CLI version | |
whoami |
Show logged-in user info (writes raw API key to stdout when piped — see Output Conventions) | |
login |
Login with browser redirect or direct user/API key (--no-browser, --no-wait, --key, --user-api-key, --org) |
|
logout |
Clear stored API key | |
signup |
Create a Composio account | |
upgrade |
Self-update binary from GitHub releases | |
init |
Bootstrap a Composio project in the current directory | |
install |
Install local-tool integrations | |
| `generate {ts | py}` | Generate type stubs (auto-detects project language if no subcommand) |
agent |
Manage AI agent presets | |
toolkits |
List / inspect / version toolkits | |
tools |
List / inspect / execute tools |
|
triggers |
List / manage trigger types | |
auth-configs |
Manage auth-config resources (ac_*) |
|
connected-accounts |
Manage connected accounts (ca_*) |
|
connections |
Alias / helper for connected-account flows | |
orgs |
Manage organizations | |
projects |
Manage projects | |
local-tools |
Manage local toolkits (via @composio/cli-local-tools) |
|
logs |
View tool-execution logs (logs-cmd/) |
|
config |
Read/write CLI config | |
listen |
Listen for events | |
proxy |
Proxy authenticated API requests | |
run |
Run a saved script / preset | |
dev |
Developer-only utilities | |
artifacts |
Manage generated artifacts |
Options use Options.text(), Options.boolean(), Options.choice(), Options.directory() with Effect Schema validation. Feature flags live in feature-tags.ts and experimental-features.ts.
Services — src/services/
| Service | Purpose |
|---|---|
ComposioUserContext |
Auth state — reads/writes ~/.composio/user-config.json, merges env vars |
ComposioSessionRepository |
Creates OAuth2 sessions, polls until linked state |
ComposioToolkitsRepository |
API client — fetches toolkits, tools, trigger types; validates versions |
ComposioToolkitsRepositoryCached |
Decorator over base repository with file-based caching and graceful fallback |
NodeOs |
OS abstraction (homedir, platform, arch) |
EnvLangDetector |
Detects project language (TS/Python) from config / lock files |
JsPackageManagerDetector |
Detects npm/pnpm/yarn/bun for install instructions |
UpgradeBinary |
Fetches latest release from GitHub, downloads and replaces binary |
OS credential storage uses the sibling package @composio/cli-keyring (macOS Keychain / Linux Secret Service).
Effects — src/effects/
Reusable Effect computations: app-config (reads COMPOSIO_* env), debug-config, force-config, setup-cache-dir, toolkit-version-overrides (parses COMPOSIO_TOOLKIT_VERSION_<NAME>=<ver>), validate-toolkit-versions, with-log-level, find-composio-core-generated, version, compare-semver, log-metrics.
Models — src/models/
Effect Schema definitions with fromJSON / toJSON helpers via JSONTransformSchema(): Toolkit, Tool, TriggerType, UserData, Session.
Code Generation — src/generation/
Pipeline for composio generate {ts,py}:
- Fetch — Toolkits, tools, trigger types (filterable via
--toolkits) - Index — Groups by toolkit prefix into
ToolkitIndex - Generate — Builds TS/Python source using
@composio/ts-buildersAST builders - Transpile — Optionally converts TS → ESM JS for
@composio/core/generated
--type-tools includes full type definitions.
Configuration
- CLI:
cli-config.ts—showBuiltIns: false,autoCorrectLimit: 0,isCaseSensitive: true - Constants:
constants.ts— env prefixes (COMPOSIO_,DEBUG_OVERRIDE_) - User config:
~/.composio/user-config.json - Cache files:
toolkits.json,tools.json,tools-as-enums.json,trigger-types.json
Key Dependencies
effect, @effect/cli, @effect/platform, @effect/platform-bun, @clack/prompts (terminal UI — stderr by default), picocolors, @composio/client (Composio API), @composio/core (types), @composio/ts-builders (AST gen), @composio/cli-keyring (OS credential store), @composio/cli-local-tools (local toolkit defs), semver, open, decompress.
Output Conventions: Composable CLI Output
Follow the Unix convention of separating human-readable decoration from machine-readable data:
- stdout — data only (
ui.output()). Captured by pipes /$(...)/> file. - stderr — all decoration (Clack spinners, logs, notes, intro/outro). Visible in terminal, invisible in pipes.
Rules:
- All
TerminalUImethods exceptoutput()write to stderr via Clack's{ output: process.stderr }, and only in interactive mode. ui.output(data)writes to stdout only when piped (checked viaprocess.stdout.isTTY).- When stdout is piped, all decoration is suppressed —
composio whoami | pbcopyis completely silent and clipboard gets the clean key. - Data commands (whoami, version, login, generate, etc.) call both decoration (stderr) and
ui.output()(stdout). - Action commands (logout, upgrade) produce no stdout data — output is purely decorative.
- Never write data to stderr or decoration to stdout.
When adding a new command: ask "Does this produce a value scripts should capture?" — yes → ui.output(value) + ui.log.*/ui.note(). No → decoration only.
Effect.ts Patterns
Generator-based syntax throughout:
Effect.gen(function* () {
const service = yield* ServiceName; // resolve dependency
const result = yield* someEffect; // await computation
yield* Effect.log('message');
return result;
});
Key patterns: Effect.all([...], { concurrency: 'unbounded' }) for parallel work, Layer.provide() for dependency composition, Effect.mapError() / Effect.catchTag() for typed errors, Effect.scoped for resource cleanup.
Vendor Reference Sources
Read-only submodules under ts/vendor/ (do NOT modify — actual deps come from npm):
ts/vendor/effect/packages/effect/src/— core Effect runtimets/vendor/effect/packages/cli/src/—@effect/cli(Command, Options, Args)ts/vendor/effect/packages/platform/src/—@effect/platformts/vendor/clack/packages/prompts/src/—@clack/prompts(text, select, confirm, spinner, note, task, etc.)ts/vendor/clack/packages/core/src/—@clack/coreprimitives
CLI Design Guidelines
Principles for arguments, flags, help, output, errors, interactivity, configuration, and exit codes:
- Use the repo-local
cli-commandskill for command design, implementation, Effect patterns, output conventions, and source-reference guidance. - Use the repo-local
cli-e2eskill for Docker-based CLI end-to-end tests underts/e2e-tests/cli/.
Use these when adding new commands or making UX decisions.
Client Cache Sync
When modifying src/services/composio-clients.ts, inspect src/services/composio-clients-cached.ts in the same change. The cached repository is a layer wrapper over ComposioToolkitsRepository; method additions, removals, signature changes, and new exported error types must stay in sync. Decide for each new method whether it should be cached or passed through. Validation-style methods are usually passthrough; fetch methods are usually cached.
Recording CLI Demos
User-facing CLI commands should ship with VHS recordings (SVG + asciicast) when the command changes a documented workflow, introduces a new visible command surface, or needs demo coverage in release notes. Small internal wiring changes and hidden developer-only helpers can skip recordings if the PR says why. Workflow:
- Add entry to
recordings/recordings.yaml(fields:name,command,description,sleepAfterEnter,height: dynamicfor long output). - Run
bun scripts/record.ts— requiresCOMPOSIO_API_KEYandvhsonPATH.
Outputs land in recordings/{tapes,svgs,ascii}/<group>/<name>.{tape,svg,ascii}.
Release Workflow
Two channels: beta (automatic) and stable (manual promotion via changeset).
Beta (automatic)
Every push to next touching ts/packages/cli/** triggers .github/workflows/build-cli-binaries.yml:
- Find latest stable
@composio/cli@X.Y.Z - Compute next patch
X.Y.Z+1 - Build cross-platform binaries (linux-x64, linux-aarch64, darwin-x64, darwin-aarch64)
- Publish GitHub prerelease
@composio/cli@X.Y.(Z+1)-beta.<run_number>
Also triggerable from any branch via workflow_dispatch → build-beta. Users install with composio upgrade --beta.
Stable (via changeset)
- Create a CLI release changeset PR only when intentionally promoting CLI binary behavior through the stable release flow (
.changeset/<name>.mdwith"@composio/cli": patch). Ordinary CLI source fixes still follow the repo rule: add a changeset only when the release path requires one. - Merge into
next - Changeset bot opens "Release: update version" PR bumping
package.json - Merge that PR → push to
nextdetects version change → builds stable release (@composio/cli@X.Y.Z, markedlatest) ts.release.ymlpublishes via the repository-controlledchangeset:releasescript, which filters@composio/clitag output so onlybuild-cli-binaries.ymlcan create CLI GitHub Releases
Promote an existing beta to stable via workflow_dispatch → promote-stable with the beta tag (e.g. @composio/cli@0.2.20-beta.42).
Key Workflow Files
.github/workflows/build-cli-binaries.yml— binary build + release.github/workflows/ts.release.yml— changeset bot + npm publish.github/workflows/cli.test-installation.yml— post-release install smoke tests.changeset/config.json