Skip to main content
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 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, change its scope, duplicate it into other scopes, set it as default, rotate manual secrets, or revoke it.
On a credential’s detail page, open the actions menu for Change scope (move the same record to another scope you can access) or Duplicate (create copies with a new name and one or more target scopes). OAuth connections open the provider’s authorization page. API key apps show a secret input and store the value in Keystroke’s credential vault.
Building over the Keystroke MCP server? 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.

Connect from the CLI

Run keystroke credentials list before connecting an app. The needed account may already be available at organization, project, or user scope. The CLI has two main paths: List connectable apps:
Connect an app. connect works for every connection type; the web flow handles OAuth or API-key entry and lets you choose the scope — there are no scope flags on connect:
In headless or hosted environments — coding agents, the in-app platform agent, CI — pass --print-url and share the printed link with the user instead of opening a browser:
For Slack, keystroke connect slack opens the same chooser as Connect Slack in the web app: the Keystroke Slack App (catalog slug slackbot), a Custom Slack App, or a Personal Slack Account (catalog slug slack). Open one dialog directly with --kind keystroke|personal|custom. For External Channels, connect the Keystroke Slack App (keystroke connect slack --kind keystroke --wait / --print-url), then keystroke channels setup <agent> — not a personal account. Custom @handles use channels setup <agent> --custom (web wizard). See external channels. Store an API key without opening a browser:
--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 — so they only apply on a local machine or CI. In hosted sessions there is no .env; use keystroke connect <slug> --print-url and let the user enter the key in the web flow.

Credential scopes

Manual credentials created with keystroke credentials create take one or more scopes. (keystroke connect picks scope in the web flow instead — the flags below apply to credentials create.) 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:
Project scope requires --project-slug because the credential must be written to a specific platform project.

Credentials and deploy

Deploy does not upload .env or local secrets. For deployed runs, set credentials 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.
A few details:
  • When several credentials could satisfy an action, choose the intended account rather than creating another connection.
  • rotate 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).

Reconnect a credential

When an OAuth credential expires or needs to be reauthorized (for example, when permissions change), use credentials reconnect to refresh the connection without creating a new credential instance:
This opens the same OAuth flow as connect, but updates the existing credential instance. Assignments, scope, and label remain unchanged — only the OAuth tokens are refreshed. In headless or hosted sessions (coding agents, CI), pass --print-url and share the printed link with the user.

Change a credential’s scope

Move an existing credential in place (same id) to a scope you can access — for example promote a user credential to a project, or a project credential to the organization. You must have access to the destination (project membership for project scope; user destination is always your own user). Use a single --scope value (unlike create, which can fan out):
Assignments that point at this credential instance keep working after a scope swap (they reference the instance id). OAuth credentials keep the same connection; only the scope changes.

Duplicate a credential

Create one or more copies of an existing credential with a new label and destination scopes. The default name is "{label} (copy)" when you omit --name / --label. Copies are never marked default.
--scope / --project-slug use the same fan-out rules as credentials create. Prefer duplicate when you need the same secret or OAuth account at another scope without reconnecting; prefer change-scope when you want a single credential to move.

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, or a user-scoped credential. An assignment pins an exact credential instance to a single consumer. It is the explicit selection at the top of the resolution order, so it wins over scope defaults. User-scoped credentials are not auto-picked from run identity. If an action is pinned with .scope("user"), assign that person’s user credential to the step, tool, or poll consumer (CLI or API). That association is what makes the run succeed. First list the bindable consumers for a workflow, agent, or poll, then assign:
  • 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:
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.

External channel apps

External channel apps connect agents to chat tools. Slack is the primary one today. Prefer the setup happy path:
Custom bot identity (dedicated @handle): keystroke channels setup support --custom opens the agent wizard. See external channels.

Next steps

Built-in integrations

Understand the app catalog and managed integration paths.

Using credentials in code

Control how actions resolve credentials at runtime.

External channels

Connect Slack channels to agents.

CLI reference

See every credential, connect, channel, and API key command.