Skip to main content
The keystroke CLI is the primary way to build, run, and operate Keystroke projects. You’ll use it to scaffold a project, deploy it to the platform, and then invoke and inspect what’s running — and optionally run it locally for offline iteration. Most commands run against an API target, either your local Keystroke server or your cloud project on the platform. Understanding how targets resolve is the key to using the CLI well. 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 20 or later.
npm install -g @keystrokehq/cli

Authentication

Authentication is shared across targets; log in once and the token is reused for every cloud command. Switching between local, cloud, or organizations does not require logging in again.
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
CommandFlagsDescription
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).

Targets: local vs cloud

Most runtime commands (workflows, agents, triggers, credentials, connect, health) resolve a target before they run:
TargetPoints atUse for
CloudThe platform control plane → your deployed projectThe default workflow: build, deploy, then run and inspect what’s deployed
LocalA local Keystroke server (keystroke dev / keystroke start)Optional escape hatch: offline, no-auth iteration on src/ without deploying
Rule of thumb: Keystroke is deploy-first. Deploy your project (a full deploy, or --filter for one module), then use the CLI against the cloud target to run and inspect what’s live. Reach for local only when you want to iterate offline without deploying.

Resolution order

The CLI picks a target in this order:
  1. --local flag → local
  2. keystroke dev session is running → local
  3. --project <slug> flag → cloud (that project only)
  4. apiTarget=local in config → local
  5. apiTarget=platform + a linked project in keystroke.config.ts → cloud
  6. Default → local
While keystroke dev is running, other commands automatically target local unless you pass --project.

Switching targets

Global CLI config lives in ~/.keystroke (apiTarget: local or platform, plus active organization). 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.
keystroke config show                 # print effective config + linked project slugs
keystroke config use local            # route to local server
keystroke config use cloud            # route to platform API
keystroke config use org              # interactively switch active organization
keystroke config use org <slug>       # switch active organization by slug
keystroke projects link --project <slug>  # link this directory to a platform project
For one-off overrides that don’t change your config, use the global flags:
keystroke --local workflows runs list greeting   # force local, just this once
keystroke --project other-app triggers list      # hit a specific cloud project once

Scaffold a project

Create a project from the default template, then deploy it.
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:
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 and keystroke docs query. Optionally, run a local server for offline iteration before you deploy:
keystroke dev                      # watch src/, rebuild, restart the API
CommandKey flagsDescription
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)
dev--dir <path>, --port <number>Watch src/, rebuild dist/, and restart the API on changes
start--dir <path>, --port <number>Build once and run the API server
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)
healthCheck connectivity to the resolved API target
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.
keystroke dev is a watch-and-restart loop, not true hot reload. On each change it rebuilds dist/ and reboots the API so newly added agents, workflows, and triggers are discovered.

Deploy

Deploy runs lint and typecheck, builds your project, uploads the dist/ artifact, and activates it on the platform. Link the directory first (or pass --project for a one-off deploy). The first successful deploy switches your default target to cloud. A lockfile in your project is not part of what ships — deploy uploads only the built dist/ tree. You do not need to run keystroke lint, keystroke typecheck, or keystroke build first — deploy is the gate.
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                           # build, upload, and deploy
keystroke deploy --project other-app       # one-off deploy to a different project
CommandKey flagsDescription
projects link--project <slug>, --dir <path>Link this directory to a platform project in keystroke.config.ts
deploy--dir <path>, --filter <entry>, --project <slug>Lint, typecheck, build, upload, and deploy the project to the platform
projects list--adminList 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, --yesDelete a project
projects metrics--project <slug>, --adminShow rollup metrics for projects
projects deployments list--project <slug>View deployment history for a project
Pass --filter <entry> to build and deploy only matching module entries on top of the active artifact, useful for fast, targeted redeploys after a full deploy.

Pull

keystroke pull is the inverse of deploy: it downloads a project’s active deploy source into a local directory and installs dependencies. Use it to start from a project that was created or deployed elsewhere — for example, onto a fresh machine.
keystroke pull --project <slug>             # into the current directory
keystroke pull --project <slug> --dir ./my-app
keystroke pull --project <slug> --force     # overwrite an existing local tree
CommandKey flagsDescription
pull--dir <path>, --forceDownload a project’s active deploy source into a local directory
pull targets the linked project in keystroke.config.ts when --project is omitted. A directory that already contains an unrelated project is refused unless you pass --force; a directory from a prior pull of the same project refreshes in place, and a pull that’s already on the active artifact exits without changes.

Invoke and inspect

Run your workflows and agents, fire triggers, and audit run history. These commands follow the resolved target: your deployed cloud project by default, or a local server if you’re running one.

Workflows

keystroke workflows list
keystroke workflows run greeting --input '{"name":"Ada"}'
keystroke workflows runs list greeting
keystroke workflows runs get greeting <run-id> --include steps,trace
keystroke workflows runs hooks greeting <run-id>
keystroke workflows runs cancel greeting <run-id>
CommandKey flagsDescription
workflows run--input <json>Invoke a workflow by key
workflows runs list--limit <n>, --cursor <cursor>, --status <s>, --trigger <t>List runs for a workflow
workflows runs get--include <parts> (trigger,steps,trace)Full details for a single run
workflows runs hooksHook tokens + resume URLs for a run
workflows runs cancel<workflow> <run-id>Cancel a running or queued run

Agents

keystroke agents list
keystroke agents prompt support --message "Hi"
keystroke agents prompt support --message "and then?" --session-id <session-id>
keystroke agents sessions get support <session-id> --include messages,trace
CommandKey flagsDescription
agents prompt--message <text>, --session-id <id>Send a message (or follow up in a session)
agents sessions list--limit <n>, --cursor <cursor>, --status <s>, --source <s>List sessions for an agent
agents sessions get--include <parts> (gateway,messages,events,trace)Full details for a single session
agents sessions cancel<agent> <session-id>Cancel a running session

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 there’s no local server or project code required.
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>. 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>.
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.
CommandKey flagsDescription
apps execute--input <json>, --version <version>, --credential <slug>, --project <slug>Run a catalog action as <app> <tool> (version defaults to the catalog)

Triggers

keystroke triggers list
keystroke triggers list --endpoint stripe   # webhooks on a shared endpoint
keystroke triggers url incoming-message     # print a webhook URL
keystroke triggers poll inbox-sync          # run a poll trigger on demand
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
CommandKey flagsDescription
triggers list--endpoint <endpoint>List discovered triggers
triggers getGet a trigger by key, or all webhooks on an endpoint
triggers urlPrint the webhook URL for a trigger
triggers poll--group, --workflow <key>, --attachment <key>Run a poll trigger on demand
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>, --workflow, --agentList runs for a trigger
triggers runs get--include <parts> (workflows,trace), --workflow, --agentFull details for a single trigger run

History (cloud)

keystroke history list --kind workflow --status failed
keystroke history get <run-id>
CommandKey flagsDescription
history list--project <id>, --status <s>, --kind <workflow|agent>List runs across projects in the organization
history getGet details for a single run

Integrations and secrets

Connect third-party accounts and manage the credentials your agents and workflows use.
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 (web flow)
keystroke credentials create exa --set apiKey=@env:EXA_API_KEY
keystroke credentials list
CommandKey flagsDescription
apps listList apps registered/connectable in your org
apps search <query>--category <c>, --limit <n>, --cursor <c>Search the live catalog
apps get <slug>Get details for one catalog app
apps actions list [slug]--search <q>List an app’s actions (or global search with no slug)
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 against the cloud
apps create--name, --slug, --description, --field <f>, --mcp <url>, --openapi <url>, --graphql <url>, --auth <kind>, --previewCreate a custom app (manual fields or auto-detect from URL)
apps sync <slug>--dir <path>Write src/apps/<name>/app.ts from the platform template
connect <slug>--print-urlOpen the web flow to connect an app (scope chosen there)
credentials list--key <key>List stored credential instances
credentials getShow a credential instance
credentials create--set <field>, --scope <scope>, --project-slug <slug>, --label <label>, --defaultCreate an api_key credential instance
credentials updateUpdate a credential instance
credentials rotateRotate a credential’s key
credentials deleteDelete 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. For credential values, --set key=value takes a literal, and --set key=@env:VAR reads from your shell (falling back to the project .env). apps create’s --field syntax is key, key:secret, key:optional, or key:secret:optional (repeatable). For manual custom apps, at least one --field is required. With --mcp, --openapi, or --graphql, auth and credential fields are auto-detected from the URL; use --preview to print the assembled request without creating, and --name, --slug, --description, --field, or --auth (MCP only) to override detected values.

Channels

Bind agents to external channels (like Slack) so people can talk to them where they already work.
keystroke channels platforms          # list supported channel platforms
keystroke channels directory          # browse bindable channels
keystroke channels list               # list current bindings
keystroke channels bind ...           # bind an agent to a channel

Organization and access

Manage members and platform API keys for your active organization. Most of these are org-admin operations.
keystroke organization members list
keystroke organization members invite --email teammate@acme.com --role builder
keystroke api-key create --name "CI"
keystroke api-key list
CommandKey flagsDescription
organization update--name <name>Rename the active organization
organization members listList 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 removeRemove a member
api-key listList org-scoped platform API keys
api-key create--name <name>Create an API key
api-key revoke-y, --yesRevoke an API key

Docs

Read the Keystroke documentation from the CLI. These commands need no authentication and no project — they work the moment the CLI is installed, for you and your coding agent alike.
keystroke docs search "webhook trigger"      # find pages by topic
keystroke docs query "cat /quickstart.mdx"   # read a page by path
CommandDescription
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 for how query works (stateless calls, output caps) and more examples.

Global options

These flags work on every command:
FlagDescription
--project <slug>Target a specific cloud project for this command (does not change your default)
--localForce the local Keystroke server for this command
--versionPrint the CLI version and exit
--helpShow help for the CLI or a specific 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.