@keystrokehq/cli 0.1.38 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/{dist-DkLbeW8l.mjs → dist-BOhrc_Nv.mjs} +198 -561
  2. package/dist/dist-BOhrc_Nv.mjs.map +1 -0
  3. package/dist/{dist-B6z1wti6.mjs → dist-D-cLLjHv.mjs} +87 -2017
  4. package/dist/dist-D-cLLjHv.mjs.map +1 -0
  5. package/dist/{dist-GSI9JDuz.mjs → dist-DGKF3FGu.mjs} +31 -265
  6. package/dist/dist-DGKF3FGu.mjs.map +1 -0
  7. package/dist/dist-DMuIdus5.mjs +3 -0
  8. package/dist/{dist-gAvgHBlr.mjs → dist-Re6HHSqz.mjs} +2 -2
  9. package/dist/{dist-gAvgHBlr.mjs.map → dist-Re6HHSqz.mjs.map} +1 -1
  10. package/dist/index.mjs +177 -463
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/{maybe-auto-update-Dv4MJvWb.mjs → maybe-auto-update-q5MthdI8.mjs} +2 -2
  13. package/dist/{maybe-auto-update-Dv4MJvWb.mjs.map → maybe-auto-update-q5MthdI8.mjs.map} +1 -1
  14. package/dist/skills-bundle/_AGENTS.mcp.md +5 -9
  15. package/dist/skills-bundle/_AGENTS.md +112 -243
  16. package/dist/skills-bundle/skills/keystroke-actions/SKILL.md +160 -0
  17. package/dist/skills-bundle/skills/keystroke-actions/references/catalog-and-imports.md +71 -0
  18. package/dist/skills-bundle/skills/keystroke-agents/SKILL.md +115 -0
  19. package/dist/skills-bundle/skills/keystroke-agents/references/models.md +23 -0
  20. package/dist/skills-bundle/skills/keystroke-agents/references/tools-mcp-codemode.md +73 -0
  21. package/dist/skills-bundle/skills/keystroke-agents/references/workflows-and-testing.md +26 -0
  22. package/dist/skills-bundle/skills/keystroke-apps/SKILL.md +151 -0
  23. package/dist/skills-bundle/skills/keystroke-apps/references/cli-and-catalog.md +104 -0
  24. package/dist/skills-bundle/skills/keystroke-channels/SKILL.md +66 -0
  25. package/dist/skills-bundle/skills/keystroke-channels/references/slack-setup.md +41 -0
  26. package/dist/skills-bundle/skills/keystroke-cli/SKILL.md +93 -0
  27. package/dist/skills-bundle/skills/keystroke-deploy/SKILL.md +93 -0
  28. package/dist/skills-bundle/skills/keystroke-deploy/references/build-and-full-deploy.md +30 -0
  29. package/dist/skills-bundle/skills/keystroke-deploy/references/filtered-deploy.md +50 -0
  30. package/dist/skills-bundle/skills/keystroke-deploy/references/wip-ignore.md +35 -0
  31. package/dist/skills-bundle/skills/keystroke-files/SKILL.md +43 -0
  32. package/dist/skills-bundle/skills/keystroke-skills/SKILL.md +42 -0
  33. package/dist/skills-bundle/skills/keystroke-triggers/SKILL.md +143 -0
  34. package/dist/skills-bundle/skills/keystroke-workflows/SKILL.md +78 -0
  35. package/dist/skills-bundle/skills/keystroke-workflows/references/authoring.md +168 -0
  36. package/dist/skills-bundle/skills/keystroke-workflows/references/testing.md +138 -0
  37. package/dist/templates/hello-world/.env.example +4 -0
  38. package/dist/templates/hello-world/README.md +3 -4
  39. package/dist/templates/hello-world/package.json +0 -1
  40. package/dist/templates/hello-world/src/actions/greet.ts +0 -1
  41. package/dist/templates/hello-world/src/agents/hello.ts +0 -2
  42. package/dist/templates/hello-world/src/workflows/greeting.ts +0 -1
  43. package/dist/{version-CiFlKPyE.mjs → version-DcR3O1UD.mjs} +3 -2
  44. package/dist/version-DcR3O1UD.mjs.map +1 -0
  45. package/package.json +5 -5
  46. package/dist/dist-B6z1wti6.mjs.map +0 -1
  47. package/dist/dist-CjWXZCN7.mjs +0 -3
  48. package/dist/dist-DkLbeW8l.mjs.map +0 -1
  49. package/dist/dist-GSI9JDuz.mjs.map +0 -1
  50. package/dist/version-CiFlKPyE.mjs.map +0 -1
@@ -1,292 +1,144 @@
1
1
  # keystroke
2
2
 
3
- This codebase is a Keystroke project. Keystroke is a code-first AI automation platform. You build AI agents, workflows, triggers, and actions in TypeScript under `src/`, deploy them to a managed cloud runtime, then run and inspect what's deployed.
3
+ This codebase is a Keystroke project.
4
4
 
5
- You are the user's AI automation engineer, the coding agent that builds and maintains this project. Read `src/` first (existing agents, workflows, actions, and triggers). Read the docs before making decisions (see [Documentation](#documentation)).
5
+ > Keystroke is a code-first AI automation platform. With it, anyone can build specialized AI agents and workflow automations in TypeScript, then deploy them to a managed cloud platform where they run.
6
6
 
7
- ## Match the user's level
7
+ - **Build agents and workflows:** Build agents and workflows with an open TypeScript framework. Run tests, connect integrations, and maintain what you build over time.
8
+ - **Connect to thousands of integrations:** Keystroke has over 1,000 built-in integrations (Slack, Google, Linear, and hundreds more). It is also extremely easy to quickly build a connection for any HTTP API (including private internal APIs) or MCP server.
9
+ - **Deploy what you build:** The Keystroke platform gives teams a managed workspace to run what they build. Deploy agents and workflows from your project. Then, view workflows on an interactive canvas, chat with agents in a chat interface, inspect runs, manage credentials, and collaborate from a shared web platform.
8
10
 
9
- Your user may or may not be technical. Keystroke users range from staff engineers to Zapier-caliber automation builders. You are the medium through which they build.
11
+ ## Keystroke projects
10
12
 
11
- - **Mirror their voice.** Only get as technical as the user does. Match their vocabulary.
12
- - **Narrate in outcomes, not plumbing.** Default to "I'll set this to run every morning and message you a summary", not "deploying the cron trigger to the runtime." Don't surface internal concepts (build artifacts, event logs, correlation IDs, filtered deploys) unless the user has to make a decision about one.
13
- - **Don't hand them the work.** They build *through* you — don't tell them to run commands, edit files, or paste code unless they've shown they want to. Do it yourself, do it quickly, and report the result.
14
- - **Simplify the talk, never the work.** Speaking plainly doesn't lower the bar — follow every invariant in this guide regardless of how the user communicates.
15
- - **If the end-state isn't clear, just ask.** It's okay to clarify how the thing you're building should be built, which integrations to use, etc.
13
+ In Keystroke, everything you build belongs to a project. A project is a shared space for building and running your agents, workflows, triggers, and actions. Think of a project as the unit you build, deploy, give credentials to, invite teammates to, and inspect run history for.
16
14
 
17
- ## Local codebase vs platform project
15
+ Keystroke projects use two related ideas:
18
16
 
19
- Keystroke separates *where you write code* from *where it runs*:
17
+ - **Local codebase**: a local directory (this codebase) with `keystroke.config.ts` and `src/` (`keystroke init` scaffolds this). Run it locally with `keystroke start` / `keystroke dev`; no platform project required.
18
+ - **Platform project**: an org-owned cloud record: a deploy target plus a hosted runtime (its own keystroke server, URL, managed credentials). Projects are inactive until their first deploy.
20
19
 
21
- | | What it is | Lives |
22
- | --- | --- | --- |
23
- | **Local codebase** | This directory — `keystroke.config.ts` + `src/`. Source of truth. | Your machine / Git |
24
- | **Platform project** | Org-owned cloud runtime (its own server, URL, credentials, run history). Inactive until first deploy. | Keystroke cloud |
20
+ `keystroke deploy --project <id>` links your local codebase to your platform project: it uploads the built local codebase and activates that platform project's server. After the first deploy the project is saved as your active target (in `~/.keystroke`), so later commands — including subsequent deploys — can drop `--project`. Deployed agents and workflows instantly run there with no additional configuration; the web workspace is where organization members can manage their projects, deployments, logs, credentials, etc.
25
21
 
26
- `keystroke deploy` builds `src/`, uploads it, and promotes it as the project's single live runtime. A deploy replaces what's running — there is no separate dev and prod within one project.
22
+ ## How this codebase fits in
27
23
 
28
- ### The web platform
24
+ This is the local codebase that defines your agents, workflows, triggers, actions, skills, context files, etc.
29
25
 
30
- Once deployed, your user works in the **web platform** — a shared workspace where they view workflows on an interactive canvas, use agents in a chat interface, inspect runs and traces, manage credentials, and collaborate with teammates. Most users spend far more time here than in code, so frame what you build around what they'll see and do there, not the CLI plumbing.
31
-
32
- ### Project layout
33
-
34
- Keystroke discovers everything under `src/` by convention.
26
+ Projects are scaffolded with an opinionated folder structure (like Next.js for building AI systems):
35
27
 
36
28
  ```
37
29
  my-app/
38
- keystroke.config.ts # project configuration
30
+ keystroke.config.ts # project configuration
39
31
  src/
40
- agents/ # LLM agents
41
- actions/ # reusable leaf units of work
42
- workflows/ # multi-step automations
43
- triggers/ # schedules, webhooks, app events
44
- skills/ # runtime playbooks for agents
45
- files/ # context files attached to agents
46
- AGENTS.md # this guide
47
- ```
48
-
49
- Each primitive imports from `@keystrokehq/keystroke/<piece>` (`/agent`, `/action`, `/workflow`, `/trigger`, `/sandbox`). Integrations are `@keystrokehq/<slug>` packages.
50
-
51
- ## The deploy-first loop
52
-
53
- Keystroke is deploy-first: build, ship, then run and inspect what's live. Deploy often.
54
-
55
- 1. **Auth once** — `keystroke auth login` (token is stored and reused).
56
- 2. **Edit** primitives under `src/`.
57
- 3. **Deploy** — `keystroke deploy` (full) or `keystroke deploy --filter agents/support` (one module).
58
- 4. **Run** — `keystroke workflow run <slug> --input '{...}'` / `keystroke agent prompt <slug> --message "..."` / `keystroke app execute <app> <tool> --input '{...}'` (connected catalog actions only).
59
- 5. **Inspect** — read the real run/trace before claiming done (see [Audit & debug](#audit--debug)).
60
- 6. Repeat.
61
-
62
- ```bash
63
- keystroke auth status # current user + org
64
- keystroke project list # your platform projects
65
- keystroke deploy # build + ship src/ (first deploy must be full)
66
- keystroke workflow run greeting --input '{"name":"Ada"}' # run a workflow
67
- keystroke agent prompt hello --message "Hi" # prompt an agent
68
- keystroke app execute github github_get_the_authenticated_user # run a connected catalog action
32
+ agents/ # LLM agents
33
+ actions/ # reusable units of work
34
+ workflows/ # multi-step automations
35
+ triggers/ # schedules, webhooks, app events
36
+ skills/ # project skills for agents
37
+ files/ # context for attaching to agents
38
+ AGENTS.md # this guide
69
39
  ```
70
40
 
71
- New project: `keystroke init my-app --yes`, then deploy. Join an existing cloud project: `keystroke pull --project <slug>`.
72
-
73
- ## Choosing a primitive
74
-
75
- | Build a… | When |
76
- | --- | --- |
77
- | **Agent** | The path isn't fixed — needs judgment, tool use, language, or multi-turn context. Or when a user is explicitly asking you to build an agent (e.g. AI data analyst for use in Slack, support agent, etc) |
78
- | **Workflow** | You know the order of steps and want durability and predictability. |
79
- | **Action** | A single reusable capability (an API call, a computation) used by workflows or agents. |
80
- | **Trigger** | Something should start a workflow/agent automatically — schedule, webhook, or poll. |
81
-
82
- Generally, prefer a workflow (or a plain action / LLM step) unless the path genuinely varies at runtime. Reach for an agent only when the user is clearly asking you to build one or when the work needs judgment, tool selection, or multi-turn context — not just because it's easier to wire up. Primitives compose: workflows orchestrate actions and prompt agents; agents call actions, subagents, and workflows as tools.
83
-
84
- ## Building blocks
85
-
86
- ### Agent — `defineAgent`
87
-
88
- Required: `slug`, `systemPrompt`, `model`. Everything else is optional.
89
-
90
- ```ts
91
- import { defineAgent } from "@keystrokehq/keystroke/agent";
92
-
93
- export default defineAgent({
94
- slug: "support",
95
- systemPrompt: "You are a helpful support assistant. Answer concisely.",
96
- model: "anthropic/claude-sonnet-4.6",
97
- });
98
- ```
99
-
100
- - **Model** — exact catalog id in `vendor/model-id` format from https://keystroke.ai/models.md. Do **not** kebab-case the version (`anthropic/claude-sonnet-4.6` is valid; `...-4-6` fails at deploy).
101
- - **Tools** — attach actions, subagents, workflows, and MCP tools directly in `tools: [...]`. Do **not** hand-roll a `defineTool` + `executeWorkflow()` wrapper. A subagent's tool name is its `slug` and takes a `message`.
102
- - **Built in**: isolated `/workspace` with file + `bash` tools, session + persistent memory (`memory: false` to disable), `web_search`/`web_fetch` when configured, self-scheduling tools.
103
- - **Credentials** are declared on actions, not agents — the agent gets them by calling those actions as tools.
104
- - **Sandbox** — default in-process bash covers most needs. For real CLIs/isolation: `sandbox: defineSandbox({ mode: "vm" })` (`mode` lives on `defineSandbox`, not as a top-level agent field).
105
-
106
- ### Workflow — `defineWorkflow`
107
-
108
- Global `slug`, typed Zod `input`/`output`, a normal `async` `run`.
109
-
110
- ```ts
111
- import { defineWorkflow } from "@keystrokehq/keystroke/workflow";
112
- import { z } from "zod";
113
-
114
- export default defineWorkflow({
115
- slug: "signup-pipeline",
116
- input: z.object({ name: z.string(), email: z.string().email() }),
117
- output: z.object({ brief: z.string() }),
118
- async run(input) {
119
- const { brief } = await researchSignup.run(input);
120
- await postBrief.run({ text: brief });
121
- return { brief };
122
- },
123
- });
124
- ```
125
-
126
- | Step | Syntax |
127
- | --- | --- |
128
- | Action | `await action.run(input)` |
129
- | Agent | `await agent.prompt({ message })` |
130
- | One-shot LLM | `await promptLlm(prompt, { model, outputSchema? })` |
131
- | Sub-workflow | `await otherWorkflow.run(input)` — never pass `ctx` |
132
- | Durable sleep | `await ctx.sleep("1h")` |
133
- | Durable wait | `await ctx.hook<T>()` |
134
-
135
- `ctx` is the second `run` argument (`async run(input, ctx)`) — add it only when a step needs `ctx.sleep`/`ctx.hook`.
136
-
137
- Use `promptLlm(...)` (import from `@keystrokehq/keystroke/workflow`) for one-shot generation/classification. Use `agent.prompt(...)` when the step needs tools, memory, or multi-turn reasoning.
138
-
139
- **Durability** — completed steps replay on retry: keep side effects inside steps; make steps idempotent; keep control flow deterministic (no `Date.now()` / randomness). Step ids are assigned automatically from each call's position in `run`, so adding or removing an unrelated step never shifts the others. `ctx.sleep`/`ctx.hook` work from triggers/CLI/HTTP but not when a workflow is inline as an agent tool.
140
-
141
- #### Canvas-legible, replayable workflows
142
-
143
- The platform renders every workflow as an interactive **canvas** (a deploy-time parser reads your source) and lights up each step in run history. These habits keep steps rendering as real nodes and keep runs replayable. Full detail: `/learn/workflows/authoring-best-practices`.
144
-
145
- **Principle** — put durable work in steps (`action.run`, `agent.prompt`, `promptLlm`, `ctx.sleep`, `ctx.hook`) and orchestrate them directly in `run` (or a same-file helper). Code between steps isn't checkpointed — it re-runs on every replay.
41
+ Keystroke discovers everything under `src/` by convention. Add a file that exports an agent, workflow, trigger, etc, and it becomes part of the project. Because the project is code, agents (Cursor, Claude Code, Codex, etc) can read it, change it, run tests, and maintain it over time.
146
42
 
147
- **Hard rules (break them and the build fails):**
43
+ Each primitive imports from `@keystrokehq/keystroke/<piece>` (`/action`, `/agent`, `/workflow`, `/trigger`, `/app`); integrations are their own `@keystrokehq/<slug>` packages. The example files in `src/` show the exact imports.
148
44
 
149
- 1. **Never call a step outside a workflow file** — a `.run()` / `.prompt()` in `src/lib/**` or any imported module is invisible and uncorrelated. Cross-file helpers are encouraged for pure logic (formatting, date math, prompt building), just don't hide steps in them.
150
- 2. **Never nest a step in another call's arguments** — hoist it first (`const p = await x.run({}); await y.run({ v: p.field })`).
45
+ ## How you work
151
46
 
152
- **Soft rules (build warns; the step still runs but renders as one opaque block):**
47
+ ### Build, deploy, test
153
48
 
154
- - Call steps **directly in `run()`**; a same-file helper is fine only if called once (reused helpers collapse).
155
- - Iterate step work with **`for-of`**, not `.map` / `.filter` / `.forEach` / `.reduce`.
156
- - Parallelize with a **literal** `Promise.all([a.run(), b.run()])`, not `Promise.all(arr.map(...))` / `race` / `allSettled` / `any`.
157
- - List step **input fields explicitly** — no `...spread` or computed `[key]:` keys.
158
- - Branch with **`if` / `else` / `switch`**, not step-bearing ternaries.
159
- - Keep all side effects and non-determinism **inside steps**.
160
- - Do HTTP/IO through an **action** (prebuilt integration *or* your own `defineAction`/`defineApp`), never a bare `fetch` in `run` — an inline `fetch` is neither a durable step nor a canvas node.
49
+ You build in `src/`, deploy to your project on the platform, then run and inspect what's deployed with the CLI. The loop is: edit `keystroke deploy` run/inspect/test repeat. You should deploy often.
161
50
 
162
- ### Action — `defineAction`
163
-
164
- Leaf unit **never calls another action** (yours or an integration's). Enforced at runtime and by lint.
165
-
166
- ```ts
167
- import { defineAction } from "@keystrokehq/keystroke/action";
168
- import { z } from "zod";
169
-
170
- export const triage = defineAction({
171
- slug: "triage",
172
- input: z.object({ message: z.string() }),
173
- output: z.object({ priority: z.enum(["low", "normal", "high", "urgent"]) }),
174
- run: async (input) => ({ priority: /urgent/i.test(input.message) ? "urgent" : "normal" }),
175
- });
176
- ```
177
-
178
- Compose in workflows. Attach integration actions directly as workflow steps or agent tools — never wrap in a custom action. An action *may* call an agent (`await agent.prompt(...)`).
179
-
180
- ### Trigger — source + `.attach()`
181
-
182
- Exactly three sources: `defineCronSource`, `defineWebhookSource`, `definePollSource`. Default-export the attached result.
183
-
184
- ```ts
185
- import { defineWebhookSource } from "@keystrokehq/keystroke/trigger";
186
- import { z } from "zod";
187
- import workflow from "../workflows/signup-pipeline";
188
-
189
- export default defineWebhookSource({
190
- slug: "signup",
191
- endpoint: "signup",
192
- request: z.object({ name: z.string(), email: z.string().email() }),
193
- }).attach({ workflow });
51
+ ```bash
52
+ keystroke auth status # show the current user and active organization
53
+ keystroke auth login # once; token is automatically stored and reused
54
+ keystroke project list # your projects on the platform
55
+ keystroke deploy --project <id> # build + ship src/ to the platform
56
+ keystroke workflow run greeting --input '{"name":"Ada"}' # test and run a workflow
57
+ keystroke agent prompt hello --message "Hi" # test and chat with an agent
194
58
  ```
195
59
 
196
- | Source | Use when |
197
- | --- | --- |
198
- | **Schedule** (`defineCronSource`) | Time alone starts the run (cron is UTC in prod). Passes `{}` — workflow `input` must accept an empty object. |
199
- | **Webhook** (`defineWebhookSource`) | Another system pushes events. Best option when available. |
200
- | **Poll** (`definePollSource`) | Keystroke must pull/check an external system on a schedule. |
60
+ After a deploy, runtime commands (`workflow`, `agent`, `trigger`, `app`, `connect`) operate on that project automatically — no target to manage.
201
61
 
202
- Filters live on the source; `transform` lives on the workflow attachment. Agents use `.attach({ agent, prompt })` (not `transform`). Attachment id: `{sourceSlug}:{targetSlug}`.
62
+ A project is a single live runtime. A deploy replaces what's running on that project — there's no separate dev and prod within one project. You can use `--filter` deploys and `@keystroke ignore` to iterate quickly.
203
63
 
204
- ## Integrations & credentials
64
+ To create a new project: `keystroke init my-app --yes`, then deploy.
205
65
 
206
- Keystroke has 1,000+ built-in integrations, and it's easy to build a custom one for any HTTP API or MCP server (including private/internal).
66
+ Look things up cheapest-first: `keystroke <command> --help` for the authoritative flags and usage of any command (local, always current); `keystroke docs search`/`query` for documentation and examples; and `/cli` for the full reference when you need broad discovery.
207
67
 
208
- Discover apps and actions with the CLI — the docs integration index is **not** reliable for discovery:
68
+ ### Building agents
209
69
 
210
- One `<app> <tool>` shape flows through discovery inspect run. `app action`/`app actions` print the next step (run, import, connect) after their output.
70
+ Agents are useful when a task needs judgment, language understanding, tool use, or multi-turn context.
211
71
 
212
- ```bash
213
- keystroke app list # all registered apps
214
- keystroke app search <query> # find an app + slug in the full catalog
215
- keystroke app actions <app> --search <q> # actions an app exposes
216
- keystroke app action <app> <tool> # schema + how to run/import one action
217
- keystroke app execute <app> <tool> --input '{...}' # run a connected catalog action (no server)
218
- keystroke connect <slug> # connect an app credential (opens web OAuth/api key flow for the user)
219
- keystroke credentials list # stored credential instances
220
- keystroke credentials set <key> --set apiKey=@env:MY_KEY # static API key
221
- ```
222
-
223
- `keystroke deploy` **never uploads `.env`** — connect cloud credentials with `keystroke connect` / `keystroke credentials set`. Missing a built-in? Use `defineCredential` + an action, `defineApp`, or `defineMcp`. See `/learn/credentials/custom-integrations`.
72
+ | Capability | How it works |
73
+ | -------------------- | --------------------------------------------------- |
74
+ | **Instructions** | `systemPrompt` tells the model how to behave |
75
+ | **Models** | `model` uses `vendor/model-id`, with optional `thinkingLevel` |
76
+ | **File system** | Each session gets a `/workspace` with a built-in file system and bash (code execution) tools |
77
+ | **Web search** | Built-in `web_search` and `web_fetch` tools when a web provider is configured |
78
+ | **Tools** | Attach custom tools, MCP tools, subagents, and workflows as tools |
79
+ | **Skills and files** | Attach skills from `src/skills/` and context files from `src/files/` |
80
+ | **Memory** | Sessions and persistent memory are enabled by default unless disabled |
81
+ | **Sandbox** | A built-in sandbox environment for using CLIs and more advanced code execution |
82
+ | **Self-scheduling** | Built-in tools let an agent schedule its own future or recurring runs (ephemeral triggers) |
224
83
 
225
- ## Skills & files
84
+ ### Building workflows
226
85
 
227
- - **Skills** (`src/skills/<name>/SKILL.md`) runtime playbooks that teach an agent *how* to do a task. Attach with `skills: ["<name>"]`.
228
- - **Files** (`src/files/<set>/`) — static context an agent can access. Attach with `sandbox: defineSandbox({ files: true })` (set folder matches the agent `slug`).
86
+ Workflows are useful when you know the order of work: call an action, prompt an agent, branch on the result, wait for approval, then continue.
229
87
 
230
- Both materialize into the agent's `/workspace/agent/...` environment before each prompt.
88
+ | Capability | How it works |
89
+ | -------------------------- | --------------------------------------------------------------------------------------------- |
90
+ | **Typed input and output** | Zod schemas validate the payload going in and the result coming out |
91
+ | **Action steps** | Call any [action](/learn/actions/overview) with `.run()`, your own or one from an integration |
92
+ | **Agent steps** | Prompt an [agent](/learn/agents/overview) with `.prompt()` when a step needs judgment |
93
+ | **LLM steps** | Use `promptLlm()` for a one-shot model call without defining a full agent |
94
+ | **Durability** | Completed steps are recorded and replayed, so retries resume instead of restarting |
95
+ | **Durable waits** | `ctx.sleep()` and `ctx.hook()` suspend a run for a delay or until it is resumed externally |
231
96
 
232
- ## Deploy targets & scope
97
+ ### Common failures
233
98
 
234
- - **Target**: after the first deploy, CLI commands target the **cloud** project automatically.
235
- - **Full vs filtered**: first deploy must be full. Use `keystroke deploy --filter agents/support` to patch one module filter keys are exact paths (`agents/support`, `workflows/morning-check`), no globs. Changing `keystroke.config.ts` or shared skills/files/integrations needs a full deploy.
236
- - **WIP**: `// @keystroke ignore` skips a file everywhere; `// @keystroke ignore:deploy` keeps it local but out of deploys. A shipped module cannot import an ignored one.
99
+ - **Research real APIs before mirroring them** — building actions for custom integrations is very common; web search and fetch the actual reference & explore relevant docs, don't guess endpoints or payload shapes.
100
+ - **Run before you claim you are finished** — deploy what you build, run it in the cloud, and read the real output before activating live triggers or claiming you are finished building something. Chat with agents to ensure they behave correctly. Run workflows to ensure they behave correctly.
101
+ - **Cover obvious edge cases** and write simple tests as needed (null field, empty array, a step that throws).
102
+ - **Connected apps aren't in `.env`** — `keystroke deploy` never uploads `.env`; connect apps (aka, integrations) for your project with `keystroke connect <slug>`.
103
+ - **Filtered deploys** — determine if you should do a full vs filtered deploy, or use WIP ignore directives.
104
+ - **Actions are leaf units** - An action never calls another action (including integration actions like `slackSendMessage`). You can compose actions in a workflow, or attach an integration action directly as a workflow step or agent tool. Action can call agents, allowing you to create "subagent tools" or "agent steps".
237
105
 
238
- ## Audit & debug
106
+ ### Audit & debug (CLI)
239
107
 
240
- Inspect deployed runs with `--include` to see full traces:
108
+ Use the CLI to inspect your deployed project.
241
109
 
242
110
  ```bash
243
- keystroke workflow runs list <workflow-slug>
244
- keystroke workflow runs get <workflow-slug> <run-id> --include steps,trace
245
-
246
- keystroke agent sessions list <agent-slug>
247
- keystroke agent sessions get <agent-slug> <session-id> --include messages,trace
248
-
249
- keystroke trigger list
250
- keystroke trigger url <trigger-slug> # webhook URL (+ ?token= on platform)
251
- keystroke trigger runs get <trigger-slug>:<workflow-slug> <run-id> --include workflows,trace
252
- keystroke trigger attachment disable <trigger-slug> <trigger-slug>:<workflow-slug> # pause without redeploy (takes both the trigger slug and the attachment id)
253
-
254
- keystroke history list --kind workflow --status failed
111
+ # Workflows
112
+ keystroke workflow list # list deployed workflows
113
+ keystroke workflow runs list <workflow-slug> # recent runs for a workflow
114
+ keystroke workflow runs get <workflow-slug> <run-id> --include steps,trace # one run in full: input, each step, execution trace
115
+
116
+ # Agents
117
+ keystroke agent list # list deployed agents
118
+ keystroke agent sessions list <agent-slug> # recent sessions for an agent
119
+ keystroke agent sessions get <agent-slug> <session-id> --include messages,trace # one session in full: messages, execution trace
120
+
121
+ # Triggers (attachment id is <trigger-slug>:<workflow-slug>)
122
+ keystroke trigger list # list deployed triggers
123
+ keystroke trigger url <trigger-slug> # print a trigger's webhook URL
124
+ keystroke trigger runs list <trigger-slug>:<workflow-slug> # recent runs for a trigger→workflow attachment
125
+ keystroke trigger runs get <trigger-slug>:<workflow-slug> <run-id> --include workflows,trace # one run in full: workflows fired, execution trace
255
126
  ```
256
127
 
257
- Invoke/inspect commands print JSON to stdout (exit 0 on success, 1 on failure) pipe to `jq`. Lifecycle commands (`init`/`dev`/`deploy`) print human status.
258
-
259
- ## Before you claim you're done
260
-
261
- - [ ] Deployed the change and read the real run output/trace — not just "it should work".
262
- - [ ] Prompted agents / ran workflows with realistic input and verified behavior.
263
- - [ ] Researched real APIs before mirroring them in custom integration actions — no guessed endpoints or payloads.
264
- - [ ] Covered obvious edge cases (null field, empty array, a step that throws) with a simple test where warranted.
265
- - [ ] Connected any new apps with `keystroke connect` (not `.env`).
266
- - [ ] Tested manually before deploying attached cron/polling triggers, or used `trigger attachment disable` to pause until ready.
267
-
268
- ## Common gotchas
269
-
270
- 1. **Action calling an action** — throws at runtime and fails lint. Compose in a workflow, or attach the integration action directly.
271
- 2. **Bad model id** — must be exact `vendor/model-id` from the catalog; don't kebab the version. Fails at deploy, not typecheck.
272
- 3. **LLM structured output: use `.nullish()`, not `.optional()`** — models emit `"field": null` for "not applicable" values, and Zod `.optional()` rejects `null` (the step fails). Use `.nullish()` (or `.nullable()`) for any optional field in an `outputSchema`.
273
- 4. **Silent fallbacks hide real failures** — for live config (Sheets, DBs, credentials), don't `catch` and quietly substitute fallback/empty data in production paths. A run that "completes" with empty inputs looks like success in the trace but is a silent failure. Throw when required config is missing or empty, and validate response shape, not just status.
274
- 5. **Side effects outside steps** — they re-run on every replay. Keep them inside `.run()` / `.prompt()`.
275
- 6. **Schedule input** — a cron trigger passes `{}`; give the workflow `input: z.object({})`.
128
+ Read `src/` first; existing agents, workflows, actions, and triggers are your best map of how this project works.
276
129
 
277
130
  ## Documentation
278
131
 
279
- Read the docs regularly and prefer them over prior knowledge. Bias **heavily** toward searching and reading documentation before making any decisions or changes. The documentation contains much more important context than this `AGENTS.md` guide.
132
+ **You should regularly and thoroughly read the documentation** when working with the CLI, building agents/workflows/triggers/actions/etc, and debugging. Bias heavily toward quickly reading documentation before making decisions or changes, and prefer what the docs say over your prior knowledge.
280
133
 
281
- All documentation is available via the CLI (no auth), cheapest-first:
134
+ Documentation is directly available via the CLI (no auth required). Use these CLI commands to search, query, and read the Keystroke documentation:
282
135
 
283
- - `keystroke <command> --help` authoritative, always-current flags for any command.
284
- - `keystroke docs search "<query>"`find pages by topic when you don't know the path.
285
- - `keystroke docs query "<cmd>"` — read/search pages with `cat`/`rg`/`ls`/`tree`/`head` (e.g. `keystroke docs query "cat /learn/agents/build-agents.mdx"`).
136
+ - **`keystroke docs search "<query>"`** — best for broad or conceptual lookups when you don't know the path (e.g. `keystroke docs search "webhook trigger"`). Returns matching pages with titles and paths; read one by passing its path to `query`.
137
+ - **`keystroke docs query "<command>"`**exact keyword/regex search, structure exploration, and reading pages by path with a shell-style command (`cat`, `rg`, `ls`, `tree`, `head`). Append `.mdx` to a doc path to read it: `keystroke docs query "cat /quickstart.mdx"`, `keystroke docs query "rg -il trigger /"`, `keystroke docs query "tree / -L 2"`.
286
138
 
287
- `query` is stateless (working dir resets to `/`; use absolute paths or chain with `&&`) and output is capped (~30KB) prefer targeted `rg -C 3` / `head` over `cat` on large pages.
139
+ Each `query` is stateless — the working dir resets to `/`, so use absolute paths or chain with `&&` and output is capped (~30KB). Prefer a targeted `rg -C 3 "term" /path.mdx` or `head -n 120 /path.mdx` over `cat` on large pages, and batch several files into one read (`head -n 80 /a.mdx /b.mdx`).
288
140
 
289
- Below is a sample of some of the most common documentation pages.
141
+ Below is a sample of common documentation pages. You can read a page with `keystroke docs query "cat <path>.mdx"`.
290
142
 
291
143
  | Doc path | Read when |
292
144
  | -------- | --------- |
@@ -300,13 +152,13 @@ Below is a sample of some of the most common documentation pages.
300
152
  | `/learn/agents/test-agents` | Testing agents locally |
301
153
  | `/learn/agents/external-channels` | Slack / external channel bindings |
302
154
  | `/learn/workflows/build-workflows` | Steps, orchestration, sandboxes |
303
- | `/learn/workflows/authoring-best-practices` | Canvas-legible, replayable workflow patterns (hard + soft rules) |
304
155
  | `/learn/workflows/test-workflows` | Workflow tests |
305
156
  | `/learn/workflows/run-workflows` | Running workflows, inspecting output |
306
157
  | `/learn/actions/overview` | Action rules (leaf units, no action-in-action) |
307
158
  | `/learn/actions/workflow-steps` | Wiring actions into workflows |
308
159
  | `/learn/actions/agent-tools` | Exposing actions as agent tools |
309
160
  | `/learn/triggers/overview` | Choosing a trigger type |
161
+ | `/learn/triggers/app-events` | App-event triggers |
310
162
  | `/learn/triggers/webhooks` | Webhook triggers |
311
163
  | `/learn/triggers/schedules` | Cron / scheduled triggers |
312
164
  | `/learn/triggers/polling` | Polling triggers |
@@ -314,7 +166,24 @@ Below is a sample of some of the most common documentation pages.
314
166
  | `/learn/credentials/connect-credentials` | `keystroke connect`, OAuth, project credentials |
315
167
  | `/learn/credentials/use-credentials` | Using connected apps in code |
316
168
  | `/learn/credentials/custom-integrations` | Building a custom HTTP / MCP / GraphQL integration |
317
- | `/learn/skills/overview` | `src/skills/` skills for agents (runtime, not this guide) |
169
+ | `/learn/skills/overview` | `src/skills/` playbooks for agents (runtime, not this guide) |
318
170
  | `/learn/skills/create-skills` | Authoring an agent skill |
319
171
  | `/learn/files/overview` | `src/files/` workspace context |
320
- | `/learn/logs/overview` | Reading run history, debugging deployed runs |
172
+ | `/learn/logs/overview` | Reading run history, debugging deployed runs |
173
+
174
+ ## Integrations and secrets
175
+
176
+ For searching native integrations use the CLI, not docs. The docs contain an index of integrations, but the documentation integration index is not reliable. To discover apps/integrations and their actions, query the live catalog with the CLI:
177
+
178
+ ```bash
179
+ keystroke app list # list all registered/supported apps
180
+ keystroke app search <query> # find an app and its slug in the full catalog
181
+ keystroke app actions <slug> --search <q> # actions an app exposes
182
+ keystroke app action <action-slug> # input/output schema for one action
183
+ keystroke connect <slug> # connect an app credential (web flow)
184
+ keystroke credentials list # List stored/available credential instances
185
+ ```
186
+
187
+ You can read `/learn/credentials/use-credentials` for using credentials in code and binding credentials to workflow steps and agent tools.
188
+
189
+ If you ever run into issues with an integration (or a required action isn't supported), it is *extremely* easy to build custom integrations and actions. You can build connections to any HTTP API or MCP server, including internal or private ones. See `/learn/credentials/custom-integrations`.
@@ -0,0 +1,160 @@
1
+ ---
2
+ name: keystroke-actions
3
+ description: Define keystroke actions — workflow steps and agent tools. Custom API actions use a credential (defineCredential) or an app wrapper (app.action); catalog integrations import from npm packages. Use when authoring src/actions/ or wiring integrations.
4
+ metadata:
5
+ keystroke-domain: actions
6
+ ---
7
+
8
+ # Actions
9
+
10
+ One **executable unit** used everywhere: workflow steps, agent tools, and codemode host calls.
11
+
12
+ Anything that calls an external API needs a **credential**. Two paths: declare a standalone `defineCredential` on a `defineAction` (simplest), or use an **app** wrapper (`app.action()`) when several actions share one connection or you've synced a catalog/custom app into `src/apps/`. See [apps skill](.agents/skills/keystroke-apps/SKILL.md).
13
+
14
+ ## Actions are leaf units — never call an action from an action
15
+
16
+ An action's `run` must **not** call another action (yours or an integration action like `slackSendMessage`). Composition belongs in a **workflow**; an integration action is used directly as a workflow step or agent tool — not wrapped in a custom action.
17
+
18
+ ```ts
19
+ // ❌ Don't: an action that calls another action
20
+ import { slackSendMessage } from "@keystrokehq/slack/actions";
21
+ export const notify = defineAction({ slug: "notify",
22
+ run: async (input) => slackSendMessage.run({ channel: input.channel, markdown_text: input.text }),
23
+ });
24
+
25
+ // ✅ Do: use the integration action directly as a workflow step
26
+ async run(input) {
27
+ return slackSendMessage.run({ channel: input.channel, markdown_text: buildText(input) });
28
+ }
29
+ ```
30
+
31
+ This is enforced at runtime (calling an action inside an action throws) and by lint (`no-restricted-imports` blocks importing `@keystrokehq/*/actions` inside `src/actions/`). An action **may** call an agent — see below.
32
+
33
+ ## Custom API actions (standalone credential)
34
+
35
+ The simplest custom integration: declare a `defineCredential` and consume it from a plain `defineAction`. No app needed.
36
+
37
+ ```ts
38
+ import { defineAction } from "@keystrokehq/keystroke/action";
39
+ import { defineCredential } from "@keystrokehq/keystroke/credentials";
40
+ import { z } from "zod";
41
+
42
+ const acme = defineCredential({ key: "acme", fields: { apiKey: z.string() } });
43
+
44
+ export const createAcmeTicket = defineAction({
45
+ slug: "create-acme-ticket",
46
+ input: z.object({ title: z.string() }),
47
+ output: z.object({ id: z.string() }),
48
+ credentials: [acme] as const,
49
+ async run(input, credentials) {
50
+ return createTicket({ apiKey: credentials.acme.apiKey, title: input.title });
51
+ },
52
+ });
53
+ ```
54
+
55
+ Connect it with `keystroke credentials set acme --set apiKey=@env:ACME_API_KEY --scope org`.
56
+
57
+ ## App-backed actions (shared connection / synced apps)
58
+
59
+ Reach for an app when several actions share one connection, or when you've synced a catalog/custom app:
60
+
61
+ 1. **App first** — create in the dashboard or `keystroke app create`, then `keystroke app sync <slug>` → `src/apps/<name>/app.ts`
62
+ 2. **Connect** — `keystroke connect <slug>` (see [apps skill](.agents/skills/keystroke-apps/SKILL.md))
63
+ 3. **Action** — `app.action()` in `src/actions/`, reading `credentials[app.slug]` in `run`
64
+
65
+ ```ts
66
+ import { z } from "zod";
67
+ import { kwatch } from "../apps/kwatch/app";
68
+
69
+ export const kwatchListAlerts = kwatch.action({
70
+ slug: "kwatch-list-alerts",
71
+ input: z.object({}),
72
+ output: z.object({ ok: z.boolean(), alertCount: z.number() }),
73
+ async run(_input, credentials) {
74
+ const { apiKey } = credentials["keystroke/kwatch"];
75
+ return { ok: true, alertCount: 0 };
76
+ },
77
+ });
78
+ ```
79
+
80
+ Use an app wrapper (over a standalone credential) when a family of actions should share one connection definition.
81
+
82
+ ## Pure actions (no credential)
83
+
84
+ Use `defineAction` with no `credentials` when the step needs no connection at all (pure logic, local transforms):
85
+
86
+ ```ts
87
+ import { defineAction } from "@keystrokehq/keystroke/action";
88
+ import { z } from "zod";
89
+
90
+ export const triage = defineAction({
91
+ slug: "triage",
92
+ name: "Triage",
93
+ description: "Classify an inbound message",
94
+ input: z.object({ message: z.string(), sender: z.string() }),
95
+ output: z.object({ priority: z.enum(["low", "normal", "high", "urgent"]) }),
96
+ run: async (input) => ({ priority: "normal" }),
97
+ });
98
+ ```
99
+
100
+ ## Catalog integration actions
101
+
102
+ Official integrations ship as npm packages with pre-built actions. Discover with `keystroke app search`, connect with `keystroke connect <slug>`, then import in workflows or agent tools — not in `src/actions/`:
103
+
104
+ ```ts
105
+ import { exaSearch } from "@keystrokehq/exa/actions";
106
+ import { slackSendMessage } from "@keystrokehq/slack/actions";
107
+ ```
108
+
109
+ Detail: [catalog-and-imports.md](references/catalog-and-imports.md).
110
+
111
+ ## Call an agent from an action (allowed)
112
+
113
+ Agents — not other actions — are the one thing an action may invoke:
114
+
115
+ ```ts
116
+ import signupResearcher from "../agents/signup-researcher";
117
+
118
+ export const researchSignup = defineAction({
119
+ slug: "research-signup",
120
+ run: async (input) => {
121
+ const result = await signupResearcher.prompt({ message: "…" });
122
+ return { brief: "…" };
123
+ },
124
+ });
125
+ ```
126
+
127
+ ## Credential scope & resolution
128
+
129
+ When a credential's scope isn't pinned, the runtime resolves it **project default first, then org default**. Pin a scope per-use with `.scope()` (the authoring-side counterpart to the CLI `--scope` flag) — it returns a fresh action that still binds like any other step/tool:
130
+
131
+ ```ts
132
+ await myAction.scope("user").run(input); // workflow step
133
+ tools: [myAction.scope("user")]; // agent tool
134
+ ```
135
+
136
+ When several instances exist for one app + scope and none is the default, pin an exact instance to the consuming step/tool from the CLI: `keystroke credentials assignments assign --workflow <slug> --credential <app>/<slug> --consumer step:<slug>#0` (see [apps skill](.agents/skills/keystroke-apps/SKILL.md)).
137
+
138
+ ## Long-running actions: honor the abort signal
139
+
140
+ `run` receives a third `ctx` argument with an `AbortSignal`. Thread it into fetches/SDK calls so the framework can cancel work cleanly:
141
+
142
+ ```ts
143
+ async run(input, credentials, ctx) {
144
+ const res = await fetch(url, { signal: ctx?.signal });
145
+ return res.json();
146
+ }
147
+ ```
148
+
149
+ ## Where actions run
150
+
151
+ | Consumer | Usage |
152
+ | -------- | ----------------------------------------------- |
153
+ | Workflow | `await myAction.run(input)` in `defineWorkflow` |
154
+ | Agent | `tools: [myAction, exaSearch]` on `defineAgent` |
155
+
156
+ ## Next references
157
+
158
+ - [catalog-and-imports.md](references/catalog-and-imports.md) — catalog discovery, npm imports
159
+
160
+ Related: [apps](.agents/skills/keystroke-apps/SKILL.md), [workflows](.agents/skills/keystroke-workflows/SKILL.md), [agents](.agents/skills/keystroke-agents/SKILL.md).