Skip to main content
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 ….
Run keystroke --help, or keystroke <command> --help, for the authoritative list of flags on any command.

Install

Install the keystroke command globally. Requires Node.js ^22.18.0 || >=24.0.0 (Node 23 is not supported).
To refresh the CLI and every project @keystrokehq/* dependency to npm latest:
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.
Your token is stored in your operating system’s secure credential store (Keychain, Credential Manager, or secret service).
auth login applies to local machines only. Hosted sessions — the in-app platform agent and MCP workspaces — have credentials injected already and cannot complete the browser device flow.

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.
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:

Scaffold a project

Create a project from the default template, then deploy it.
Or seed the link at init time:
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 and keystroke docs query.
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.

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.
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.
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

See workflow 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

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.
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).
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>.
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.

Triggers

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

History (cloud)

Integrations and secrets

Connect third-party accounts and manage the credentials your agents and workflows use.
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. 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. LLM provider API keys (BYOK for model inference) are not app credentials — connect those with keystroke managed-services instead.

Managed services (cloud)

Bring your own LLM provider API keys for organization-wide inference. See Managed services.

Channels

Bind agents to external channels (like Slack) so people can talk to them where they already work. See external channels.
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.

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.
See 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.
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 }. See CLI for agents 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.

Using the CLI with AI 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.