> ## Documentation Index
> Fetch the complete documentation index at: https://keystroke.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# CLI reference

> Full reference for the Keystroke CLI.

The `keystroke` CLI is the primary way to build, deploy, and operate Keystroke projects. You'll use it to scaffold a project, ship it to the platform, and then invoke and inspect what's running there.

Keystroke is deploy-first: edit your codebase, deploy, then run and inspect against your **cloud** project on the platform.

**Command shape** — resource collections use plural names (matching the HTTP API): `keystroke <collection> <verb> [<slug>]`. Examples: `keystroke workflows run greeting`, `keystroke triggers disable inbound-email-poll`, `keystroke apps execute github …`.

<Tip>
  Run `keystroke --help`, or `keystroke <command> --help`, for the authoritative list of flags on any command.
</Tip>

## Install

Install the `keystroke` command globally. Requires [Node.js](https://nodejs.org) `^22.18.0 || >=24.0.0` (Node 23 is not supported).

<CodeGroup>
  ```bash npm theme={null}
  npm install -g @keystrokehq/cli
  ```

  ```bash pnpm theme={null}
  pnpm add -g @keystrokehq/cli
  ```

  ```bash yarn theme={null}
  yarn global add @keystrokehq/cli
  ```

  ```bash bun theme={null}
  bun add -g @keystrokehq/cli
  ```
</CodeGroup>

To refresh the CLI and every project `@keystrokehq/*` dependency to npm `latest`:

```bash theme={null}
keystroke update
```

`keystroke deploy` / `build` / `lint` / `typecheck` require those packages to be current and will tell you to run `keystroke update` when they are not.

## Authentication

Log in once and the token is reused for every command. Switching organizations does not require logging in again.

```bash theme={null}
keystroke auth login              # browser device flow; auto-picks your org
keystroke auth login --org <slug> # log in and select a specific organization
keystroke auth status             # show the current user and active organization
keystroke auth logout             # clear stored credentials
```

| Command       | Flags                                                     | Description                              |
| ------------- | --------------------------------------------------------- | ---------------------------------------- |
| `auth login`  | `--org <slug>`, `--web-url <url>`, `--platform-url <url>` | Authenticate via the browser device flow |
| `auth status` | `--web-url <url>`                                         | Print authentication status as JSON      |
| `auth logout` | `--web-url <url>`                                         | Remove the stored access token           |

Your token is stored in your operating system's secure credential store (Keychain, Credential Manager, or secret service).

<Note>
  `auth login` applies to local machines only. Hosted sessions — the in-app [platform agent](/docs/build-with-ai/platform-agent) and [MCP](/docs/build-with-ai/mcp-for-agents) workspaces — have credentials injected already and cannot complete the browser device flow.
</Note>

## Project targeting

Most runtime commands (`workflows`, `agents`, `triggers`, `credentials`, `connect`, `health`) run against your deployed cloud project on the platform. There is no local CLI API server — every HTTP command uses the configured platform URL.

**Which platform project you deploy to** is stored in the project's `keystroke.config.ts` as optional `project` and `organization` slugs — set by `keystroke projects link` or `keystroke init --project`. Global CLI config lives in `~/.keystroke`.

```bash theme={null}
keystroke config show                 # print effective web/platform URLs + linked project slugs
keystroke config org                  # list organizations you belong to
keystroke config preferences get      # show account preferences (JSON)
keystroke projects link --project <slug>  # link this directory to a platform project
```

| Command                          | Description                                                           |
| -------------------------------- | --------------------------------------------------------------------- |
| `config show`                    | Print `webUrl`, effective `platformUrl`, and linked project/org slugs |
| `config org`                     | List organizations you belong to                                      |
| `config preferences get` / `set` | Read or update account preferences                                    |

Defaults are `https://keystroke.ai` (web) and `https://api.keystroke.ai` (platform). Switch environments with `keystroke auth login --web-url <url>` and optional `--platform-url <url>` — both persist in `~/.keystroke`. Local dashboard: `--web-url http://localhost:3000` (platform URL derives automatically when known).

For a one-off override that doesn't change your config, pass [`--project`](#global-options):

```bash theme={null}
keystroke --project other-app triggers list      # hit a specific cloud project once
```

## Scaffold a project

Create a project from the default template, then [deploy](#deploy) it.

```bash theme={null}
keystroke init my-app --yes        # scaffold a project from the default template
cd my-app
keystroke projects link --project <slug>  # link this directory to a platform project
keystroke deploy                    # lint + typecheck + build + ship dist/
```

Or seed the link at init time:

```bash theme={null}
keystroke init my-app --yes --project <slug> --organization <org-slug>
```

`keystroke init` creates `keystroke.config.ts`, a committed `tsconfig.json` (extends `@keystrokehq/cli/tsconfig.json`), a `src/` directory with an example agent, and an `AGENTS.md` guide so your coding agent knows how Keystroke works. Lint, typecheck, and test tooling (oxlint, TypeScript, vitest, `@types/node`) ship inside `@keystrokehq/cli` — projects do not declare them or ship `.oxlintrc.json` / `vitest.config.ts`. `AGENTS.md` is versioned to your CLI — commands run inside the project re-sync it automatically after a CLI update. For deeper context, use [`keystroke docs search`](/docs/cli#docs) and [`keystroke docs query`](/docs/cli#docs).

| Command     | Key flags                                                                                                                          | Description                                                           |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `init`      | `--name <name>`, `--template <name>`, `-y, --yes`, `--skip-install`, `--pm <manager>`, `--project <slug>`, `--organization <slug>` | Create a new project from a template (`--yes` for headless/agent use) |
| `build`     | `--dir <path>`                                                                                                                     | Build the project for production                                      |
| `lint`      | `--dir <path>`                                                                                                                     | Lint `src/` with bundled oxlint (config lives in the CLI)             |
| `typecheck` | `--dir <path>`                                                                                                                     | Type-check with bundled TypeScript using the project `tsconfig.json`  |
| `test`      | `--dir <path>`, `[args...]`                                                                                                        | Run tests with bundled vitest (`--project unit` or `integration`)     |
| `update`    | `--dir <path>`                                                                                                                     | Update `@keystrokehq/*` project deps and the CLI to latest            |
| `health`    |                                                                                                                                    | Check connectivity to the platform                                    |

<Note>
  `package.json` scripts (`pnpm lint`, `pnpm typecheck`, `pnpm test`) call these commands. Config files stay in the CLI bundle — nothing is written into your project when you run them.
</Note>

## Deploy

For **managed-Git** projects, the CLI compares the pinned `main` and draft commits locally, analyzes filtered impact, then acquires a platform deploy lease and ships the candidate artifact. Expanded or unknown filtered impact requires confirmation or `--accept-impact`. For **snapshot-only** projects, deploy runs lint and typecheck, builds, uploads the `dist/` artifact, and activates it. Link the directory first (or pass `--project` for a one-off deploy). After deploy, runtime commands target your linked cloud project.

You do not need to run `keystroke lint`, `keystroke typecheck`, or `keystroke build` first — deploy runs the required checks and build.

```bash theme={null}
keystroke projects list                     # list projects in your organization
keystroke projects create --name "My app"   # create a deploy target
keystroke projects link --project <slug>    # write project + org slugs to keystroke.config.ts
keystroke deploy                           # preflight, build, upload, and activate
keystroke deploy --accept-impact --filter workflows/ping   # accept expanded/unknown impact
keystroke deploy --build-from-workspace    # build against local monorepo packages
keystroke deploy --project other-app       # one-off deploy to a different project
```

| Command                     | Key flags                                                                                           | Description                                                        |
| --------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `projects link`             | `--project <slug>`, `--dir <path>`                                                                  | Link this directory to a platform project in `keystroke.config.ts` |
| `deploy`                    | `--dir <path>`, `--filter <entry>`, `--accept-impact`, `--build-from-workspace`, `--project <slug>` | Preflight, build, upload, and activate a deploy                    |
| `projects list`             | `--admin`                                                                                           | List projects in the active organization                           |
| `projects create`           | `--name <name>`, `--description <desc>`                                                             | Create a platform project                                          |
| `projects update`           | `--name <name>`, `--description <desc>`                                                             | Update a project's name or description                             |
| `projects delete`           | `-y, --yes`                                                                                         | Delete a project                                                   |
| `projects metrics`          | `--project <slug>`, `--admin`                                                                       | Show rollup metrics for projects                                   |
| `projects deployments list` | `--project <slug>`                                                                                  | View deployment history for a project                              |

Pass `--filter <entry>` with workflow/agent keys (`workflows/…`, `agents/…`). Managed filtered deploys analyze shared dependencies locally and may require confirmation (`--accept-impact` in non-TTY). Snapshot filtered deploys merge a targeted local build into the active artifact.

For a project nested in a package-manager monorepo, `--build-from-workspace` builds against the current checkout so `workspace:`, `link:`, and local `file:` dependencies resolve. This escape hatch only supports full deploys and local package sources are not captured in Keystroke's managed source, so the artifact is not reproducible from that source alone. Prefer published dependency versions when possible.

## Pull

`keystroke pull` fetches the shared unpublished draft (`ks/draft`) and merges it into your local checkout, then installs dependencies. Pass `--published` to fetch the exact commit on the active deploy instead. Managed Git state lives in `.keystroke/git`, so your configured remotes are left unchanged.

```bash theme={null}
keystroke pull --project <slug>             # into the current directory
keystroke pull --project <slug> --dir ./my-app
keystroke pull --project <slug> --published # active published revision
```

| Command | Key flags                     | Description                                                       |
| ------- | ----------------------------- | ----------------------------------------------------------------- |
| `pull`  | `--dir <path>`, `--published` | Merge the shared draft, or the active revision with `--published` |

`pull` targets the linked project in `keystroke.config.ts` when `--project` is omitted. Git-less directories are bootstrapped into the managed sidecar. If the merge conflicts, Git leaves conflict markers in place — resolve them, `git add`, and `git commit` (or `git merge --abort`). Legacy snapshot-only artifacts still use the bulk source download when `--published` is set.

## Invoke and inspect

Run your workflows and agents, fire triggers, and audit run history against your deployed cloud project.

### Workflows

```bash theme={null}
keystroke workflows list
keystroke workflows run greeting --input '{"name":"Ada"}' --wait --timeout 60
keystroke workflows runs list greeting
keystroke workflows runs get greeting <run-id> --wait --timeout 60
keystroke workflows runs get <run-id> --summary
keystroke workflows runs get greeting <run-id> --field output
keystroke workflows runs get greeting <run-id> --include steps,trace,children
keystroke workflows runs hooks greeting <run-id>
keystroke workflows runs cancel greeting <run-id>
keystroke workflows forms list
keystroke workflows forms publish greeting --title "Greeting"
keystroke workflows forms url greeting
```

| Command                     | Key flags                                                                                                                  | Description                                                                                |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `workflows run`             | `--input <json>`, `--wait`, `--timeout <seconds>`, `--summary` (with `--wait`)                                             | Invoke a workflow and optionally wait for completion                                       |
| `workflows runs list`       | `--limit <n>`, `--cursor <cursor>`, `--status <s>`, `--trigger <t>`                                                        | List runs for a workflow                                                                   |
| `workflows runs get`        | `--wait`, `--timeout <seconds>`, `--summary`, `--field <field>`, `--include <parts>` (`trigger,steps,trace,children,none`) | Inspect a run; waiting requires `<workflow> <run-id>`                                      |
| `workflows runs hooks`      |                                                                                                                            | Hook tokens + resume URLs for a run                                                        |
| `workflows runs cancel`     | `<workflow> <run-id>`                                                                                                      | Cancel a running or queued run                                                             |
| `workflows forms list`      | `--admin`                                                                                                                  | List forms in scope (`--admin` ignores linked project; explicit `--project` still narrows) |
| `workflows forms get`       |                                                                                                                            | Get a workflow's form JSON                                                                 |
| `workflows forms url`       |                                                                                                                            | Print a published form's public URL                                                        |
| `workflows forms publish`   | `--title`, `--description`, `--config <json>`, `--field-config <json>`                                                     | Publish or update a public form                                                            |
| `workflows forms unpublish` |                                                                                                                            | Stop accepting form submissions                                                            |
| `workflows forms rotate`    |                                                                                                                            | Rotate a form's public link token                                                          |

See [workflow forms](/docs/learn/workflows/forms) for when to use forms, field presentation, and dashboard publish.

`--wait` is bounded and defaults to 60 seconds for workflows. Set a different duration with `--timeout <seconds>`. If the timeout elapses, the command returns the latest running state with exit code `0`; continue with `workflows runs get <workflow> <run-id> --wait`. A failed or canceled run exits with code `1`.

### Agents

```bash theme={null}
keystroke agents list
keystroke agents prompt support --message "Hi" --wait --timeout 120
keystroke agents prompt support --message "and then?" --session-id <session-id> --wait
keystroke agents sessions get support <session-id> --wait --timeout 120
keystroke agents sessions get support <session-id> --summary
keystroke agents sessions get support <session-id> --include messages,trace
```

| Command                  | Key flags                                                                                                                   | Description                                       |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
| `agents prompt`          | `--message <text>`, `--session-id <id>`, `--wait`, `--timeout <seconds>`, `--summary` (with `--wait`)                       | Send a message and optionally wait for completion |
| `agents sessions list`   | `--limit <n>`, `--cursor <cursor>`, `--status <s>`, `--source <s>`                                                          | List sessions for an agent                        |
| `agents sessions get`    | `--wait`, `--timeout <seconds>`, `--summary`, `--field <field>`, `--include <parts>` (`gateway,messages,events,trace,none`) | Inspect a session or continue waiting for it      |
| `agents sessions cancel` | `<agent> <session-id>`                                                                                                      | Cancel a running session                          |

Agent waits default to 120 seconds. A wait timeout means the session is still running and exits with code `0`; continue with `agents sessions get <agent> <session-id> --wait`. Failed and canceled sessions exit with code `1`.

### Actions

Discover and run catalog actions with a single `<app> <tool>` shape at every step — find → inspect → run. Credentials stay in the cloud; the CLI proxies execution through `/mcp/execute`, so no project code is required.

```bash theme={null}
keystroke apps actions list github --search user                       # find tool slugs for an app
keystroke apps actions get github github_get_the_authenticated_user    # inspect schema + how to run/import
keystroke apps execute github github_get_the_authenticated_user   # run it
keystroke apps execute acculynx acculynx_add_job_appointment --input '{"jobId":"123","startDate":"2026-01-01T09:00:00Z","endDate":"2026-01-01T10:00:00Z"}'
```

`apps actions list` and `apps actions get` print next steps (run ad-hoc, import into code, connect) after their output. Slugs are case-insensitive. If the app is not connected, `apps execute` exits with a hint to run `keystroke connect <app>`.

**Catalog vs custom org apps.** Built-in catalog apps (`github`, `exa`, …) expose toolkit actions you can list/execute. Custom org apps (`{org}/{name}`, from `apps create`) are credential templates — their runnable TypeScript actions live in your project as `defineApp(...).action(...)`. Custom MCP apps support live `apps actions list` and `apps execute` against the remote server (see below).

| Command                    | Catalog app (`github`)                           | Custom MCP (`my-org/example-mcp`)                                          | Other custom org app (`wells/demo-echo`)                             |
| -------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `apps get <slug>`          | `{ kind: "catalog", app: { name, package, … } }` | `{ kind: "custom", app: { …, source: "mcp", … } }`                         | `{ kind: "custom", app: { slug, authKind, credentialFields, … } }`   |
| `apps actions list <slug>` | Ready toolkit actions (`kind: "catalog"`)        | Live remote `tools/list` (`kind: "mcp"`) — **not** authored TypeScript yet | Guidance only (`kind: "custom"`) — use `apps sync` / project actions |
| `apps execute`             | Supported                                        | Supported (remote `tools/call`; no `--version`)                            | Not applicable — run your workflow/agent instead                     |
| `apps actions get`         | Supported                                        | Not applicable — inspect via `apps actions list`                           | Not applicable                                                       |

```bash theme={null}
keystroke apps get github                     # catalog toolkit package
keystroke apps get wells/demo-echo            # custom credential template
keystroke apps actions list github            # ready toolkit actions
keystroke apps actions list my-org/example-mcp  # after connect: every remote MCP tool (may lack TS wrappers)
keystroke apps execute my-org/example-mcp list_accounts --input '{}'
keystroke apps actions list wells/demo-echo   # explains there are no catalog tools
```

Credential resolution matches the runtime: it uses the **project default**, then the **org default**. Project credentials only resolve when you target a project with the global `--project <slug>` flag (or run inside a linked project); without it, only org credentials resolve. **User credentials are never a default** — reach one explicitly with `--credential <slug>`.

```bash theme={null}
keystroke apps execute github github_get_the_authenticated_user                   # org default
keystroke apps execute github github_get_the_authenticated_user --project my-app   # project default (falls back to org)
keystroke apps execute github github_get_the_authenticated_user --credential work-github  # pin a specific instance by slug
```

Pass `--credential <slug>` to pin a specific instance when a scope has more than one — the slug is the one you set with `keystroke credentials create <key> --slug <slug>` and can see with `keystroke credentials list`. It's also the only way to use a user-scoped credential.

| Command        | Key flags                                                                          | Description                                                            |
| -------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| `apps execute` | `--input <json>`, `--version <version>`, `--credential <slug>`, `--project <slug>` | Run a catalog action or custom MCP tool (`--version` for catalog only) |

### Triggers

```bash theme={null}
keystroke triggers list
keystroke triggers list --endpoint stripe   # webhooks on a shared endpoint
keystroke triggers url incoming-message     # print a webhook URL
keystroke triggers invoke inbox-sync        # fire a poll/cron/webhook on demand
keystroke triggers invoke signup --input '{"email":"a@b.com"}'
# invoke returns { runId, triggerSlug, targets }; then:
keystroke triggers runs get signup <runId>  # workflowRuns[] once dispatched
keystroke triggers runs list inbound-email-poll
keystroke triggers runs list inbound-email-poll --workflow signup-pipeline
keystroke triggers disable signup                        # pause the trigger (all attachments)
keystroke triggers disable signup --workflow signup-pipeline   # pause just one attachment
keystroke triggers enable signup                         # resume
```

| Command              | Key flags                                                                                                   | Description                                                                                                                                                        |
| -------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `triggers list`      | `--endpoint <endpoint>`                                                                                     | List discovered triggers                                                                                                                                           |
| `triggers get`       |                                                                                                             | Get a trigger by key, or all webhooks on an endpoint                                                                                                               |
| `triggers url`       |                                                                                                             | Print the webhook URL for a trigger                                                                                                                                |
| `triggers invoke`    | `--input <json>`, `--workflow <slug>`, `--agent <slug>`                                                     | Manually invoke a trigger (platform only; `--input` is webhook-only). Returns trigger `runId` + `targets` (workflow run ids appear later via `triggers runs get`). |
| `triggers disable`   | `--workflow <slug>`, `--agent <slug>`                                                                       | Pause a trigger — all attachments, or one target                                                                                                                   |
| `triggers enable`    | `--workflow <slug>`, `--agent <slug>`                                                                       | Resume a trigger — all attachments, or one target                                                                                                                  |
| `triggers runs list` | `--limit <n>`, `--cursor <cursor>`, `--trigger-type <type>`, `--outcome <outcome>`, `--workflow`, `--agent` | List runs for a trigger (`--outcome` is `dispatched`, `skipped`, or `failed`)                                                                                      |
| `triggers runs get`  | `--include <parts>` (`workflows,trace`), `--workflow`, `--agent`                                            | Full details for a single trigger run                                                                                                                              |

Machine-oriented commands print JSON on stdout and human hints on stderr (so `| jq` stays clean).

### History (cloud)

```bash theme={null}
keystroke history list --kind workflow --status failed
keystroke history get <run-id>
```

| Command        | Key flags                                                    | Description                                   |
| -------------- | ------------------------------------------------------------ | --------------------------------------------- |
| `history list` | `--project <id>`, `--status <s>`, `--kind <workflow\|agent>` | List runs across projects in the organization |
| `history get`  |                                                              | Get details for a single run                  |

## Integrations and secrets

Connect third-party accounts and manage the credentials your agents and workflows use.

```bash theme={null}
keystroke apps list                                  # apps registered in your org
keystroke apps search "github"                       # search the live catalog
keystroke apps actions list github --search issue         # actions an app exposes
keystroke connect google                            # connect an app (opens the web flow)
keystroke connect google --print-url                # headless: print the URL to share instead
keystroke credentials create exa --set apiKey=@env:EXA_API_KEY
keystroke credentials list
```

| Command                         | Key flags                                                                                                                                             | Description                                                                                                                                     |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `apps list`                     |                                                                                                                                                       | List apps registered/connectable in your org                                                                                                    |
| `apps search "{query}"`         | `--category <c>`, `--limit <n>`, `--cursor <c>`                                                                                                       | Search the live catalog                                                                                                                         |
| `apps get <slug>`               |                                                                                                                                                       | Get one app: catalog toolkit (`kind:catalog`) or custom org template (`kind:custom`)                                                            |
| `apps actions list [slug]`      | `--search <q>`                                                                                                                                        | Catalog: toolkit actions. Custom MCP (after connect): live remote tools (`kind:mcp`) — not TypeScript yet. Other custom: `kind:custom` guidance |
| `apps actions get <app> <tool>` |                                                                                                                                                       | Full input/output schema for one action, plus run/import hints                                                                                  |
| `apps execute <app> <tool>`     | `--input <json>`, `--version <version>`, `--credential <slug>`, `--project <slug>`                                                                    | Run a connected catalog action or custom MCP tool                                                                                               |
| `apps create`                   | `--name`, `--slug`, `--description`, `--logo <url>`, `--field <f>`, `--mcp <url>`, `--openapi <url>`, `--graphql <url>`, `--auth <kind>`, `--preview` | Create a custom app (manual fields or auto-detect from URL)                                                                                     |
| `apps delete <slug>`            |                                                                                                                                                       | Delete a custom org app and its credentials                                                                                                     |
| `apps sync <slug>`              | `--dir <path>`                                                                                                                                        | Write `src/apps/<name>/app.ts` from the platform template                                                                                       |
| `connect <slug>`                | `--print-url`, `--kind <kind>`, `--wait`                                                                                                              | Open the web flow to connect an app (scope chosen there)                                                                                        |
| `credentials list`              | `--key <key>`                                                                                                                                         | List stored credential instances                                                                                                                |
| `credentials get`               |                                                                                                                                                       | Show a credential instance                                                                                                                      |
| `credentials create`            | `--set <field>`, `--scope <scope>`, `--project-slug <slug>`, `--label <label>`, `--default`                                                           | Create an `api_key` credential instance                                                                                                         |
| `credentials reconnect`         | `--print-url`                                                                                                                                         | Open the web flow to reconnect an existing credential (or print the URL in headless environments)                                               |
| `credentials update`            | `--label`, `--default`, `--set <field>`, `--scope <scope>`, `--project-slug <slug>`                                                                   | Rename, set default, rotate secret fields, or move scope in place (single `--scope`)                                                            |
| `credentials duplicate`         | `--name` / `--label`, `--scope <scope>`, `--project-slug <slug>`                                                                                      | Copy a credential into one or more scopes (`"{name} (copy)"` if unnamed)                                                                        |
| `credentials rotate`            |                                                                                                                                                       | Rotate a credential's key                                                                                                                       |
| `credentials delete`            |                                                                                                                                                       | Delete a credential instance                                                                                                                    |

`connect` requires an app slug (see `keystroke apps list` for connectable slugs) and chooses scope in the web flow — scope and project pinning are set on `credentials create`, not `connect`. In headless or hosted sessions (coding agents, the in-app platform agent, CI), always pass `--print-url` and hand the printed URL to the user — those environments cannot open a browser. `connect slack` opens the three-way Slack chooser; `--kind keystroke|personal|custom` opens one dialog directly (`keystroke` = the Keystroke Slack App — catalog slug `slackbot`, `personal` = Personal Slack Account, `custom` = Custom Slack App wizard), and `--wait` (Keystroke Slack App only) polls until the gateway workspace registers. For credential values, `--set key=value` takes a literal, and `--set key=@env:VAR` reads from your shell (falling back to the project `.env`). `credentials update --scope` moves one existing instance (exactly one of `org`, `user`, or `project`); `credentials duplicate` fans out copies like `create`. See [connect and manage apps](/docs/learn/credentials/connect-credentials#change-a-credentials-scope). `apps create`'s `--field` syntax is `key`, `key:secret`, `key:optional`, or `key:secret:optional` (repeatable). For manual custom apps, `--name` and at least one `--field` are required; `--description` defaults to `--name` when omitted. Optional `--logo <url>` sets a public image URL for the Apps catalog (same as **Logo URL** in the web create dialog). Example: `keystroke apps create --name Acme --description "Internal Acme API" --logo https://example.com/acme-logo.png --field apiKey:secret`. With `--mcp`, `--openapi`, or `--graphql`, auth and credential fields are auto-detected from the URL (this registers a connectable org catalog app, not only local scaffolding); use `--preview` to print the assembled request without creating, and `--name`, `--slug`, `--description`, `--logo`, `--field`, or `--auth` (MCP only) to override detected values. After create, connect with `keystroke connect <slug>`, then author actions with `defineApp` / `apps sync` — see [custom apps and MCP](/docs/learn/credentials/custom-integrations).

LLM provider API keys (BYOK for model inference) are **not** app credentials — connect those with [`keystroke managed-services`](#managed-services-cloud) instead.

## Managed services (cloud)

Bring your own LLM provider API keys for organization-wide inference. See [Managed services](/docs/learn/settings/managed-services).

```bash theme={null}
keystroke managed-services list
keystroke managed-services connect xai --api-key "xai-..."
keystroke managed-services update xai --api-key "xai-..."
keystroke managed-services disconnect xai
```

| Command                                  | Key flags         | Description                                                         |
| ---------------------------------------- | ----------------- | ------------------------------------------------------------------- |
| `managed-services list`                  | `--kind <kind>`   | List connected provider keys                                        |
| `managed-services connect <provider>`    | `--api-key <key>` | Connect a provider (`openai`, `anthropic`, `google`, `groq`, `xai`) |
| `managed-services update <provider>`     | `--api-key <key>` | Rotate the key for a connected provider                             |
| `managed-services disconnect <provider>` |                   | Disconnect a provider and fall back to platform keys                |

## Channels

Bind agents to external channels (like Slack) so people can talk to them where they already work. See [external channels](/docs/learn/agents/external-channels).

```bash theme={null}
keystroke connect slack --kind keystroke --wait      # Keystroke Slack App OAuth; wait until workspace appears
keystroke channels setup support --channel support   # create/bind Keystroke path
keystroke channels setup support --custom            # open custom-app wizard URL
keystroke channels platforms list
keystroke channels accounts --platform slack
keystroke channels directory --platform slack --account <team-id>
keystroke channels list support
keystroke channels bind support --platform slack --account <team-id> --channel <id>
keystroke channels unbind support <binding-id>
keystroke channels update-binding support <binding-id> --replies mentions
```

`channels bind` / `update-binding` use `--replies mentions|mentions-followups` (same choices as the External Channels UI). Bind defaults to `mentions-followups`.

## Organization and access

Manage members and platform API keys for your active organization. Most of these are org-admin operations.

```bash theme={null}
keystroke organization members list
keystroke organization members invite --email teammate@acme.com --role builder
keystroke api-key create --name "CI"
keystroke api-key list
```

| Command                       | Key flags                          | Description                           |
| ----------------------------- | ---------------------------------- | ------------------------------------- |
| `organization update`         | `--name <name>`                    | Rename the active organization        |
| `organization members list`   |                                    | List members                          |
| `organization members invite` | `--email <email>`, `--role <role>` | Invite members (`admin` or `builder`) |
| `organization members role`   | `--role <role>`                    | Change a member's role                |
| `organization members remove` |                                    | Remove a member                       |
| `api-key list`                |                                    | List org-scoped platform API keys     |
| `api-key create`              | `--name <name>`                    | Create an API key                     |
| `api-key revoke`              | `-y, --yes`                        | Revoke an API key                     |

## Docs

Read the Keystroke documentation from the CLI. These commands need **no authentication, organization, project, or config** — they work the moment the CLI is installed, for you and your coding agent alike.

```bash theme={null}
keystroke docs search "webhook trigger"      # find pages by topic
keystroke docs query "cat /quickstart.mdx"   # read a page by path
```

| Command                | Description                                                                             |
| ---------------------- | --------------------------------------------------------------------------------------- |
| `docs search <query>`  | Search the docs for relevant pages and examples                                         |
| `docs query <command>` | Read the docs filesystem with a shell-style command (`cat`, `rg`, `ls`, `tree`, `head`) |

See [docs for agents](/docs/build-with-ai/docs-for-agents) for how `query` works (stateless calls, output caps) and more examples.

## Feedback

Coding agents can report build friction directly to the Keystroke team. Use this after a build loop when the agent encountered unclear documentation, confusing errors, unexpected framework constraints, missing capabilities, or non-obvious workarounds.

`feedback create` requires authentication and an active organization. The platform attaches the signed-in user's identity and organization automatically; the CLI also includes its version and the linked project slug when available.

```bash theme={null}
keystroke feedback create --message "$(cat <<'EOF'
*Quick Recap and Context*

We were building a workflow that turns a social media post into a structured roleplay scenario.

-------------------------

*Feedback for Keystroke Team*

*1. One-action-per-file only failed at deploy*
We grouped related actions in one file because local build passed. Deploy rejected it, so we split the actions into separate files. Catching this during lint or documenting it more prominently would have saved a deploy cycle.
EOF
)"
```

The message is freeform; the recap and numbered feedback above are a suggested structure. Write it for a Keystroke team member with zero context on the session: plain language first, technical detail (paths, commands, error text) second, one numbered item per issue. Run `keystroke feedback create --help` for the full writing guide. Do not include secrets, tokens, credentials, private source dumps, proprietary code, or personal data from project files or user inputs. Success prints `{ "ok": true }`.

| Command           | Key flags          | Description                                                |
| ----------------- | ------------------ | ---------------------------------------------------------- |
| `feedback create` | `--message <text>` | Send an authenticated build-experience report to Keystroke |

See [CLI for agents](/docs/build-with-ai/cli-for-agents#report-build-friction) for when coding agents should use this command.

## Global options

`--project` applies to platform-targeting commands; docs commands ignore organization/project scope. `--version` and `--help` work on every command.

| Flag               | Description                                                                     |
| ------------------ | ------------------------------------------------------------------------------- |
| `--project <slug>` | Target a specific cloud project for this command (does not change your default) |
| `--version`        | Print the CLI version and exit                                                  |
| `--help`           | Show help for the CLI or a specific command                                     |

<Card title="Using the CLI with AI agents" href="/docs/build-with-ai/cli-for-agents">
  Keystroke is built for coding agents. Learn how agents use the CLI, the docs commands, and headless mode to build and operate your project.
</Card>
