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

# Connect and manage apps

> Connect apps, API keys, and OAuth accounts from the web app or CLI.

You can connect apps and manage credentials from either the web app or the CLI. Use the web app when you want a guided flow. Use the CLI when you're scripting setup, working locally, or setting project-scoped credentials during deploy work.

## Connect from the web app

Open **Apps** in the web app to see connected apps and add new ones.

The Apps page is organized around credential instances: each connected app row represents a credential at an organization, project, or user scope. From there you can:

* Connect an OAuth app (click "Connect an app" to see all available apps, and select an app to create a new connection).
* Store an API key for an app.
* Choose where the credential is available: organization, user, or selected projects.
* Rename a credential, set it as default, rotate manual secrets, or revoke it.

OAuth connections open the provider's authorization page. API key apps show a secret input and store the value in Keystroke's credential vault.

<Note>
  Building over the [Keystroke MCP server](/build-with-ai/mcp-for-agents)? The agent's `connect_app` tool returns a link to this same web flow — a hosted workspace can't open a browser, so you authorize the integration here.
</Note>

## Connect from the CLI

The CLI has two main paths:

| Command                           | Use it for                                   |
| --------------------------------- | -------------------------------------------- |
| `keystroke connect <slug>`        | OAuth-style connections, such as Slack       |
| `keystroke credentials set <key>` | Static API keys and manually-entered secrets |

List connectable apps:

```bash theme={null}
keystroke apps list
```

Connect an app. `connect` opens the web flow (OAuth approval or an API-key form, depending on the app), where you also choose the scope — there are no scope flags on `connect`:

```bash theme={null}
keystroke connect slack
```

Store an API key:

```bash theme={null}
keystroke credentials set exa --set apiKey=@env:EXA_API_KEY --scope org
```

`--set` accepts either an inline value (`apiKey=sk-...`) or an environment reference (`apiKey=@env:EXA_API_KEY`). Environment references load from the shell and the project's `.env` file when available.

## Credential scopes

Manual credentials set with `keystroke credentials set` take one or more scopes. (OAuth connections made with `keystroke connect` pick their scope in the web flow instead — the flags below apply to `credentials set`.)

| Scope flag                              | Meaning                                        |
| --------------------------------------- | ---------------------------------------------- |
| `--scope org`                           | Create an organization credential              |
| `--scope user`                          | Create a credential for the authenticated user |
| `--scope project --project-slug <slug>` | Create a credential for one project            |

If you omit `--scope`, the CLI creates an organization credential.

You can repeat `--scope` and `--project-slug` to fan out one credential to several targets:

```bash theme={null}
keystroke credentials set exa \
  --set apiKey=@env:EXA_API_KEY \
  --scope org \
  --scope project \
  --project-slug production \
  --project-slug staging
```

Project scope requires `--project-slug` because the credential must be written to a specific platform project.

## Local vs cloud

Credentials follow the CLI's active target:

```bash theme={null}
# Local server credential
keystroke --local credentials set exa --set apiKey=@env:EXA_API_KEY

# Cloud platform credential
keystroke credentials set exa --set apiKey=@env:EXA_API_KEY --scope project --project-slug production
```

Deploy does not upload `.env` or local credentials. For deployed runs, set credentials against the cloud target with the web app or CLI. Workers materialize the selected credential from the platform when an action runs.

## Manage credentials

Use the Apps page for day-to-day management, or use CLI commands when scripting.

```bash theme={null}
keystroke credentials list
keystroke credentials get <credential-id>
keystroke credentials update <credential-id> --label "Production Exa" --default
keystroke credentials rotate-key <credential-id> --set apiKey=@env:EXA_API_KEY
keystroke credentials delete <credential-id>
```

A few details:

* `rotate-key` is for cloud credentials and replaces a manual secret value.
* `update --default` marks one credential as the default within its app and scope.
* If multiple credentials exist for the same app and scope and none is the single default, a run needs an explicit selection — bind one with an assignment (below).

## Bind a credential to a step, tool, or poll action

A default resolves the common case, but sometimes one workflow step, agent tool, or poll action must use a *specific* instance — a particular project's Linear connection, a dedicated service account, one of several org credentials. An **assignment** pins an exact credential instance to a single consumer. It is the explicit selection at the top of the [resolution order](/learn/credentials/use-credentials#resolution-order), so it wins over scope defaults.

First list the bindable consumers for a workflow, agent, or poll, then assign:

```bash theme={null}
# Workflow consumers are step correlation ids from recent runs (step:<slug>#<n>)
keystroke credentials consumers list --workflow sync
keystroke credentials assignments assign --workflow sync --credential org/work --consumer step:fetch-gmail#0

# Agent consumers are tool slugs
keystroke credentials consumers list --agent support
keystroke credentials assignments assign --agent support --credential vault-prod --consumer vault-lookup

# Poll consumers are the slugs of actions called inside the poll's run()
keystroke credentials consumers list --poll new-inbox
keystroke credentials assignments assign --poll new-inbox --credential gmail/support --consumer fetch-inbox
```

* Pass exactly one of `--workflow <slug>`, `--agent <slug>`, or `--poll <slug>`.
* `--credential` takes a credential instance slug: `work`, `org/work`, or `<app>/<slug>` (for example `linear/work`).
* Omit `--consumer` (or pass `*`) to bind every consumer on the target instead of one.

Inspect and remove assignments:

```bash theme={null}
keystroke credentials assignments list --workflow sync
keystroke credentials assignments unassign <assignment-id>
```

<Note>
  Workflow consumer ids come from `step_completed` events, so they appear only after the workflow has run at least once. Agent consumers include known tool slugs plus any from existing assignments. Poll consumers only come from existing assignments — name the action slug explicitly (or use the wildcard) on the first assign.
</Note>

## External channel apps

External channel apps connect agents to chat tools. Slack is the primary one today. You connect Slack like any other app, then bind channels to agents from the agent's channel panel or the CLI:

```bash theme={null}
keystroke channels bind \
  --agent support \
  --platform slack \
  --account <workspace-id> \
  --channel <channel-id> \
  --mode mention
```

See [external channels](/learn/agents/external-channels) for the agent-facing Slack setup.

## Next steps

<CardGroup cols={2}>
  <Card title="Built-in integrations" href="/learn/credentials/built-in-integrations">
    Understand the app catalog and managed integration paths.
  </Card>

  <Card title="Using credentials in code" href="/learn/credentials/use-credentials">
    Control how actions resolve credentials at runtime.
  </Card>

  <Card title="External channels" href="/learn/agents/external-channels">
    Connect Slack channels to agents.
  </Card>

  <Card title="CLI reference" href="/cli">
    See every credential, connect, channel, and API key command.
  </Card>
</CardGroup>
