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 ….
Install
Install thekeystroke command globally. Requires Node.js 20 or later.
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.| 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 |
Targets: local vs cloud
Most runtime commands (workflows, agents, triggers, credentials, connect, health) resolve a target before they run:
| Target | Points at | Use for |
|---|---|---|
| Cloud | The platform control plane → your deployed project | The default workflow: build, deploy, then run and inspect what’s deployed |
| Local | A local Keystroke server (keystroke dev / keystroke start) | Optional escape hatch: offline, no-auth iteration on src/ without deploying |
--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:--localflag → localkeystroke devsession is running → local--project <slug>flag → cloud (that project only)apiTarget=localin config → localapiTarget=platform+ a linked project inkeystroke.config.ts→ cloud- Default → local
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.
Scaffold a project
Create a project from the default template, then deploy it.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:
| 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) |
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) |
health | Check 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 thedist/ 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.
| 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>, --project <slug> | Lint, typecheck, build, upload, and deploy the project to the platform |
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 |
--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.
| Command | Key flags | Description |
|---|---|---|
pull | --dir <path>, --force | Download 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
| Command | Key flags | Description |
|---|---|---|
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 hooks | Hook tokens + resume URLs for a run | |
workflows runs cancel | <workflow> <run-id> | Cancel a running or queued run |
Agents
| Command | Key flags | Description |
|---|---|---|
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.
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>.
--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 as <app> <tool> (version defaults to the catalog) |
Triggers
| 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 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, --agent | List runs for a trigger |
triggers runs get | --include <parts> (workflows,trace), --workflow, --agent | Full details for a single trigger run |
History (cloud)
| 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.| 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 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>, --preview | Create 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-url | 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 update | Update a credential instance | |
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. 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.Organization and access
Manage members and platform API keys for your active organization. Most of these are org-admin operations.| 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 and no project — they work the moment the CLI is installed, for you and your coding agent alike.| 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) |
query works (stateless calls, output caps) and more examples.
Global options
These flags work on every command:| Flag | Description |
|---|---|
--project <slug> | Target a specific cloud project for this command (does not change your default) |
--local | Force the local Keystroke server for this command |
--version | Print the CLI version and exit |
--help | Show 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.