Free SKILL.md scraped from GitHub. Clone the repo or copy the file directly into your Claude Code skills directory.
npx versuz@latest install composiohq-composio-agents-skills-create-cligit clone https://github.com/ComposioHQ/composio.gitcp composio/SKILL.MD ~/.claude/skills/composiohq-composio-agents-skills-create-cli/SKILL.md---
description: CLI design guidelines — arguments, flags, subcommands, help, output, errors, interactivity, config precedence. Apply when designing new commands or reviewing CLI UX.
globs:
- "ts/packages/cli/src/**/*.ts"
alwaysApply: false
---
# CLI Design Guidelines
Design CLI surface area (syntax + behavior), human-first, script-friendly.
Adapted from [clig.dev](https://clig.dev/) for our TypeScript + Effect.ts + Clack stack.
## When to Use
- Designing a CLI spec (before implementation) or refactoring CLI surface area.
- Adding new commands, flags, or interactive prompts.
- Reviewing CLI UX decisions.
After designing a command, use the `implement-cli-command` skill to build it.
After implementation, use the `create-cli-e2e` skill to write end-to-end tests.
## Stack & Architecture
See `ts/packages/cli/AGENTS.md` for the full architecture reference, including dependencies, services, effects, and vendor submodule locations.
## Output Conventions
The CLI separates human-readable decoration from machine-readable data. See `ts/packages/cli/AGENTS.md` § "Output Conventions" for the full specification.
Key rule: when adding a command, ask "Does this produce a value scripts should capture?"
- **Yes** → `ui.output(value)` for data, `ui.log.*` / `ui.note()` for context.
- **No** → Only `ui.log.*` / `ui.note()` / `ui.intro()` / `ui.outro()`.
**Show state changes.** When a command modifies state, say what changed and the new state:
```typescript
// After logout:
yield* ui.log.info('Removed API key from ~/.composio/user-config.json');
// After generate:
yield* ui.log.success('Generated 42 tools across 5 toolkits → src/generated/');
```
## Arguments & Flags
Define options via `@effect/cli`:
```typescript
const toolkits = Options.text('toolkits').pipe(
Options.optional,
Options.withDescription('Comma-separated toolkit slugs'),
);
const force = Options.boolean('force').pipe(
Options.withAlias('f'),
Options.withDefault(false),
);
```
Principles:
- Prefer flags over positional args for clarity and extensibility.
- Provide long versions of all flags; one-letter aliases only for the most common.
- Default values should be right for most users.
- Never accept secrets via flags — they leak to `ps` output and shell history. Use `--password-file`, stdin, or a secret manager instead.
- Support `-` for stdin/stdout when input/output is a file path.
Standard flag names:
| Flag | Short | Purpose |
| ---- | ----- | ------- |
| `--help` | `-h` | Show help (built-in via @effect/cli) |
| `--version` | | Print version to stdout |
| `--quiet` | `-q` | Less output |
| `--verbose` | `-v` | More output (never use `-v` for version) |
| `--debug` | `-d` | Debug output |
| `--force` | `-f` | Skip confirmations |
| `--dry-run` | `-n` | Preview only |
| `--json` | | Structured output |
| `--output` | `-o` | Output file path |
| `--no-input` | | Disable prompts; fail if required input missing |
| `--no-browser` | | Skip browser-open steps |
| `--no-color` | | Disable color output |
## Subcommands
```typescript
const login = Command.make('login', { noBrowser }, handler);
const generate = Command.make('generate', { toolkits, typeTools }, handler);
const root = Command.make('composio').pipe(
Command.withSubcommands([login, generate, /* ... */]),
);
```
- Follow verb-noun pattern consistently: `composio login`, `composio generate`.
- Share global flags via parent command composition.
- Support `composio help <subcmd>` and `composio <subcmd> --help`.
- Avoid ambiguous pairs (`update` vs `upgrade`) unless sharply differentiated.
## Interactivity
Use `@clack/prompts` for all interactive UI. All Clack output goes to stderr via `{ output: process.stderr }`.
| Prompt | When to use |
| ------ | ----------- |
| `text()` | Free-form text input |
| `password()` | Secret input (echo disabled) |
| `confirm()` | Yes/no decisions |
| `select()` | Choose one from a list |
| `multiselect()` | Choose multiple from a list |
| `spinner()` | Long-running operations |
| `log.info/warn/error/step()` | Styled status messages |
| `note()` | Boxed contextual info |
| `intro()` / `outro()` | Session start/end markers |
Rules:
- Prompt only if stdin is a TTY.
- `--no-input`: never prompt; fail with actionable message if required input missing.
- Make escape hatches obvious (Ctrl-C).
- Destructive operations: interactive confirmation + non-interactive requires `--force`.
## Error Handling
- Use the `effect-errors/` module for capture and formatting.
- Catch and rewrite expected errors for humans; no stack traces by default.
- Put the most important info last; use red intentionally.
- For unexpected crashes: provide debug info path + bug report instructions.
**Write actionable error messages.** Tell the user *what went wrong* and *how to fix it*:
```
// Bad:
Error: EACCES
// Good:
Can't write to ~/.composio/user-config.json.
You might need to fix permissions: chmod +w ~/.composio/user-config.json
// Bad:
Error: 401
// Good:
API key is invalid or expired.
Run `composio login` to authenticate again.
```
**Suggest corrections** when the user mistypes a subcommand or flag. If they ran `composio genrate`, suggest `composio generate`.
Exit codes:
| Code | Meaning |
| ---- | ------- |
| `0` | Success |
| `1` | Generic failure |
| `2` | Invalid usage (parse/validation error) |
## Help & Documentation
- `@effect/cli` generates help text from Command/Options declarations.
- If run with missing required args, show concise help + 1–2 examples + "use --help for more".
- Lead with examples; show common flags first.
- Link to docs URL per subcommand when applicable.
- Provide both terminal help (offline, version-synced) and web docs (searchable, linkable).
Good help text structure:
```
USAGE
$ composio generate [--toolkits <slugs>] [--type-tools]
OPTIONS
--toolkits <slugs> Comma-separated toolkit slugs (default: all)
--type-tools Generate full type definitions
-o, --output <dir> Output directory (default: @composio/core/generated)
EXAMPLES
$ composio generate
$ composio generate --toolkits github,slack --type-tools
COMMANDS
composio generate ts Generate TypeScript stubs
composio generate py Generate Python stubs
```
**Suggest next commands** when it helps the user's flow:
```
✔ Logged in as user@example.com
Next: run `composio generate` to generate type stubs for your toolkits.
```
## Configuration Precedence
High to low: **flags > process env > project config > user config > system config**.
- Composio prefixes: `COMPOSIO_*` for app config, `DEBUG_OVERRIDE_*` for debug.
- User config stored in `~/.composio/`.
- Respect common env vars: `NO_COLOR`, `DEBUG`, `EDITOR`, `PAGER`, `TERM`, `TMPDIR`, `HOME`.
## Naming
- Subcommand names: simple, lowercase, single word when possible.
- Avoid too-generic names that collide with system tools.
- Keep names short but not cryptic — easy to type matters.
- Never create implicit catch-all subcommands that prevent future expansion.
- Don't allow arbitrary abbreviations (reserving `g` for `generate` blocks future `g`-commands).
- Use explicit aliases only when there's a clear, stable mapping.
## Robustness & Performance
- Validate early; fail fast with good error messages.
- Print something within ~100ms (especially before network I/O). Start a Clack spinner immediately before any network call.
- Show progress for long tasks (interactive only) via Clack spinners.
- Use timeouts for network calls; allow configuration.
- Make reruns safe: idempotent where possible; recoverable on failure.
- **Crash-only design**: assume cleanup might not run. Defer cleanup to the next invocation rather than relying on shutdown hooks. If a cache file is half-written, the next run should detect and rebuild it.
## Example Invocations
```bash
# Interactive — user sees Clack decoration on stderr
composio login
composio generate --toolkits github,slack
# Piped — only data on stdout, no decoration
composio whoami | pbcopy
API_KEY=$(composio whoami)
composio version | cat
# Non-interactive with force
composio logout --force --no-input
# Debug mode
composio generate --debug --verbose
```
## References
- Community CLI Guidelines: https://clig.dev/
- CLI architecture: `ts/packages/cli/AGENTS.md`
- @effect/cli source: `ts/vendor/effect/packages/cli/src/`
- @clack/prompts source: `ts/vendor/clack/packages/prompts/src/`