@keystrokehq/cli 0.1.15 → 0.1.16

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 (31) hide show
  1. package/dist/index.mjs +7 -4
  2. package/dist/index.mjs.map +1 -1
  3. package/dist/skills-bundle/_AGENTS.mcp.md +10 -3
  4. package/dist/skills-bundle/_AGENTS.md +61 -70
  5. package/dist/skills-bundle/skills/keystroke-actions/SKILL.md +60 -12
  6. package/dist/skills-bundle/skills/keystroke-actions/references/catalog-and-imports.md +32 -3
  7. package/dist/skills-bundle/skills/keystroke-agents/SKILL.md +50 -8
  8. package/dist/skills-bundle/skills/keystroke-agents/references/models.md +11 -13
  9. package/dist/skills-bundle/skills/keystroke-agents/references/tools-mcp-codemode.md +45 -3
  10. package/dist/skills-bundle/skills/keystroke-agents/references/workflows-and-testing.md +1 -1
  11. package/dist/skills-bundle/skills/keystroke-apps/SKILL.md +26 -13
  12. package/dist/skills-bundle/skills/keystroke-apps/references/cli-and-catalog.md +47 -16
  13. package/dist/skills-bundle/skills/keystroke-channels/SKILL.md +66 -0
  14. package/dist/skills-bundle/skills/keystroke-channels/references/slack-setup.md +41 -0
  15. package/dist/skills-bundle/skills/keystroke-cli/SKILL.md +41 -93
  16. package/dist/skills-bundle/skills/keystroke-deploy/SKILL.md +10 -9
  17. package/dist/skills-bundle/skills/keystroke-deploy/references/build-and-full-deploy.md +3 -1
  18. package/dist/skills-bundle/skills/keystroke-deploy/references/filtered-deploy.md +3 -2
  19. package/dist/skills-bundle/skills/keystroke-deploy/references/wip-ignore.md +5 -2
  20. package/dist/skills-bundle/skills/keystroke-files/SKILL.md +12 -4
  21. package/dist/skills-bundle/skills/keystroke-skills/SKILL.md +7 -2
  22. package/dist/skills-bundle/skills/keystroke-triggers/SKILL.md +30 -17
  23. package/dist/skills-bundle/skills/keystroke-workflows/SKILL.md +27 -12
  24. package/dist/skills-bundle/skills/keystroke-workflows/references/authoring.md +116 -4
  25. package/dist/skills-bundle/skills/keystroke-workflows/references/testing.md +17 -9
  26. package/dist/templates/hello-world/README.md +19 -8
  27. package/dist/templates/hello-world/src/workflows/greeting.test.ts +1 -1
  28. package/package.json +2 -2
  29. package/dist/skills-bundle/skills/keystroke-cli/references/api-targets.md +0 -87
  30. package/dist/skills-bundle/skills/keystroke-gateways/SKILL.md +0 -43
  31. package/dist/skills-bundle/skills/keystroke-gateways/references/slack-setup.md +0 -27
@@ -1,12 +1,12 @@
1
1
  # keystroke (MCP)
2
2
 
3
- Keystroke is an AI automation server for agents and workflows.
3
+ Keystroke is a code-first AI automation platform build specialized AI agents and workflow automations as real TypeScript, then deploy them to a managed cloud where they run. Everything is actual code (not brittle JSON), so agents can build, test, and maintain it. There are 1,000+ built-in integrations (Slack, Google, Linear, …), and you can build a connection for any HTTP API (including private internal APIs) or MCP server.
4
4
 
5
5
  You are editing a **keystroke project** in a remote workspace via MCP. Author under `src/`, import from `@keystrokehq/*` npm packages. You do not have framework source — only this project and published deps.
6
6
 
7
7
  Use MCP tools to work on the project: `read_file`, `write_file`, `edit_file`, `list_files`, `delete_file`, `exec_command`, and `deploy_project`. Load authoring guidance with `search_skills` and `get_skill` (see skills map below). The workspace root also has `AGENTS.md` and `.agents/skills/` with the same skill content, readable via `read_file`.
8
8
 
9
- The **keystroke platform** is the hosted control plane. After you change code, run `deploy_project` to build and upload; that activates the cloud runtime.
9
+ The **keystroke platform** is the hosted control plane. After you change code, run `deploy_project` to build and upload; that activates the cloud runtime. 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), so use filtered deploys and `@keystroke ignore` to iterate quickly.
10
10
 
11
11
  ## What you build
12
12
 
@@ -26,6 +26,10 @@ Draft or in-progress modules, full vs filtered deploy, and `@keystroke ignore`:
26
26
 
27
27
  **Actions are leaf units.** An action never calls another action (including integration actions like `postMessage`). Compose actions in a workflow, or attach an integration action directly as a workflow step / agent tool. An action may call an agent.
28
28
 
29
+ **Workflow steps.** Workflows orchestrate actions, agent prompts, and LLM calls (`promptLlm`) as steps. There's no first-class "call another workflow" step — share logic by extracting it into `src/lib/` or an action, or expose a workflow as an agent tool (`defineWorkflowTool`) / over HTTP when you want it as its own tracked run.
30
+
31
+ **Agent tools.** Agents can use actions, subagents (`defineSubagentTool`), workflows (`defineWorkflowTool`), and MCP tools as tools.
32
+
29
33
  ## Working habits
30
34
 
31
35
  A few things that are easy to skip and cause common failures:
@@ -46,7 +50,10 @@ keystroke workflow run <workflow-key> --input '{}'
46
50
  keystroke workflow runs list <workflow-key>
47
51
  keystroke workflow runs get <workflow-key> <run-id> --include steps,trace
48
52
  keystroke agent sessions list <agent-key>
53
+ keystroke agent sessions get <agent-key> <session-id> --include messages,trace
49
54
  keystroke trigger list
55
+ keystroke trigger url <trigger-key>
56
+ keystroke trigger runs list <trigger-key>:<workflow-key>
50
57
  keystroke app list
51
58
  ```
52
59
 
@@ -64,7 +71,7 @@ Call `search_skills` then `get_skill` with the key below.
64
71
  | `keystroke-workflows` | Orchestration, action steps |
65
72
  | `keystroke-actions` | Shared steps, integration tools |
66
73
  | `keystroke-triggers` | Cron, webhook, poll automation |
67
- | `keystroke-gateways` | Slack / messaging bindings |
74
+ | `keystroke-channels` | Slack / external channel bindings |
68
75
  | `keystroke-skills` | `src/skills/` playbooks |
69
76
  | `keystroke-files` | Agent workspace files |
70
77
  | `keystroke-apps` | Connectable apps, catalog, connect |
@@ -1,121 +1,112 @@
1
1
  # keystroke
2
2
 
3
- Keystroke is an AI automation server for agents and workflows.
3
+ This codebase is a Keystroke project.
4
4
 
5
- You are in a **keystroke project**. Author under `src/`, import from `@keystrokehq/*` npm packages. You do not have framework source only your project and published deps.
5
+ > Keystroke is a code-first AI automation platform, an n8n alternative built for agents. With it, anyone can build specialized AI agents and workflow automations as real TypeScript, then deploy them to a managed cloud platform where they run. Unlike tools like Zapier and n8n that hide logic behind brittle JSON, everything in Keystroke is actual code that coding agents (Cursor, Claude Code, Codex, etc.) can build, test, and maintain.
6
6
 
7
- A **keystroke server** runs this project (`keystroke start` / `keystroke dev`). The **keystroke platform** is the hosted control plane that manages many keystroke servers after deploy.
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). You can also 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 inspect runs, manage credentials, and collaborate from a shared web platform.
8
10
 
9
- ## Local vs cloud (CLI)
11
+ ## Keystroke projects
10
12
 
11
- The CLI routes runtime commands to one of two API targets:
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 into, and inspect run history for.
12
14
 
13
- | Target | Use for |
14
- | --------------------------------------------- | -------------------------------------------------------------------------------------------------- |
15
- | **Local** (default `:3002`) | **Development and testing** — iterate on `src/`, run workflows/agents on your machine |
16
- | **Cloud** (`platformUrl` + `activeProjectId`) | **Invoking and listing deployed resources** — production runs, triggers, remote audit after deploy |
15
+ Keystroke projects use two related ideas:
17
16
 
18
- ```bash
19
- keystroke dev # local; other commands auto-target local while this runs
20
- keystroke config use local # switch to local (cloud project id is preserved)
21
- keystroke config use cloud # switch back to deployed project
22
- keystroke config use project <id> # swap active cloud project
23
- keystroke --project <id> workflow run foo --input '{}' # one-off cloud target
24
- keystroke config show # inspect activeProjectId, apiTarget, dev session
25
- keystroke project list # platform deploy targets in the active org
26
- keystroke project create --name "My app" # new target (inactive until deploy)
27
- keystroke deploy --project <id> # build + upload; activates cloud runtime
28
- ```
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.
29
19
 
30
- `keystroke auth login` oncetoken is shared; switching targets does not require re-auth.
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 users can manage their projects, deployments, logs, credentials, etc.
31
21
 
32
- **Platform project** = cloud deploy target (managed by the control plane). **Local project** = this repo (`src/`, `keystroke.config.ts`). You need a platform project id before `keystroke deploy`.
22
+ ## How this codebase fits in
33
23
 
34
- Full routing rules: [cli skill](.agents/skills/keystroke-cli/SKILL.md) [api-targets.md](.agents/skills/keystroke-cli/references/api-targets.md).
24
+ This is the local codebase that defines your agents, workflows, triggers, actions, skills, and files.
35
25
 
36
- ## Run locally (fastest path)
26
+ Projects are scaffolded with an opinionated folder structure (like Next.js for building AI systems):
37
27
 
38
- ```bash
39
- # .env is created from .env.example on init — set ANTHROPIC_API_KEY + integration keys
40
- keystroke start # API :3002, dashboard :3000
41
- keystroke health
42
- keystroke agent prompt hello --message "Hi"
28
+ ```
29
+ my-app/
30
+ keystroke.config.ts # project configuration
31
+ src/
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
39
+ .agents/skills/ # Keystroke skills and best practices
43
40
  ```
44
41
 
45
- New project: `keystroke init my-app --yes`, then the steps above.
42
+ 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.
46
43
 
47
- ## CLI auth
44
+ 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.
48
45
 
49
- ```bash
50
- keystroke auth login
51
- ```
46
+ ## How you work
52
47
 
53
- Required for cloud/platform commands and some trigger operations. Not required for typical local dev without auth enabled.
48
+ 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.
54
49
 
55
- ## What you build
50
+ ```bash
51
+ keystroke auth login # once; token is automatically stored and reused
52
+ keystroke project list # your projects on the platform
53
+ keystroke deploy --project <id> # build + ship src/ to the platform
54
+ keystroke workflow run greeting --input '{"name":"Ada"}' # run on your project
55
+ keystroke agent prompt hello --message "Hi"
56
+ ```
56
57
 
57
- | Piece | Where | Import from |
58
- | -------------- | -------------------------------------- | --------------------------------------------------------------------------- |
59
- | Actions | `src/actions/` | `@keystrokehq/keystroke/action` |
60
- | Agents | `src/agents/` | `@keystrokehq/keystroke/agent` |
61
- | Workflows | `src/workflows/` | `@keystrokehq/keystroke/workflow` |
62
- | Triggers | `src/triggers/` | `@keystrokehq/keystroke/trigger` |
63
- | Apps | `src/apps/` | `@keystrokehq/keystroke/app`, `keystroke app`, `keystroke connect` |
64
- | Integrations | npm packages + catalog | `@keystrokehq/exa`, `@keystrokehq/slack`, … — discover with `keystroke app search` |
65
- | Skills / files | `src/skills/`, `src/files/` | attached on `defineAgent` |
58
+ After a deploy, runtime commands (`workflow`, `agent`, `trigger`, `app`, `connect`) operate on that project automatically — no target to manage.
66
59
 
67
- Default-export each modulethe server discovers files under `src/`.
60
+ 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 keep iterate quickly.
68
61
 
69
- Draft or in-progress modules, full vs filtered deploy, and `@keystroke ignore`: [deploy skill](.agents/skills/keystroke-deploy/SKILL.md).
62
+ To create a new project: `keystroke init my-app --yes`, then deploy.
70
63
 
71
- **Actions are leaf units.** An action never calls another action (including integration actions like `postMessage`). Compose actions in a workflow, or attach an integration action directly as a workflow step / agent tool. An action may call an agent.
64
+ Full deploy mechanics: [cli skill](.agents/skills/keystroke-cli/SKILL.md), [deploy skill](.agents/skills/keystroke-deploy/SKILL.md).
72
65
 
73
66
  ## Working habits
74
67
 
75
68
  A few things that are easy to skip and cause common failures:
76
69
 
77
70
  - **Research real APIs before mirroring them** — web search and fetch the actual reference & explore relevant docs; don't guess endpoints or payload shapes.
78
- - **Run before you depend or deploy** — run the workflow/agent locally and read the real output (`keystroke workflow runs get <key> <run-id> --include steps,trace`) before wiring dependent steps.
71
+ - **Run before you depend on it** — run the workflow/agent and read the real output (`keystroke workflow runs get <workflow-slug> <run-id> --include steps,trace`) before wiring dependent steps or claiming you are finished building something.
79
72
  - **Cover obvious edge cases** and write simple tests as needed (null field, empty array, a step that throws) — see [workflows skill](.agents/skills/keystroke-workflows/SKILL.md).
80
- - **Connected apps aren't in `.env`** — `keystroke deploy` never uploads `.env`; connect apps on the cloud target with `keystroke connect <slug>`. See [apps skill](.agents/skills/keystroke-apps/SKILL.md).
81
- - **Shipping to prod** — full vs filtered deploy, WIP ignore directives: [deploy skill](.agents/skills/keystroke-deploy/SKILL.md).
73
+ - **Connected apps aren't in `.env`** — `keystroke deploy` never uploads `.env`; connect apps (aka, integrations) for your project with `keystroke connect <slug>`. See [apps skill](.agents/skills/keystroke-apps/SKILL.md).
74
+ - **Shipping to prod** — determine if you should do a full vs filtered deploy, or use WIP ignore directives: [deploy skill](.agents/skills/keystroke-deploy/SKILL.md).
75
+ - **Actions are leaf units** - An action never calls another action (including integration actions like `slackSendMessage`). Compose actions in a workflow, or attach an integration action directly as a workflow step / agent tool. An action may call an agent.
76
+ - **Workflow steps** - Workflows orchestrate actions, agent prompts, and LLM calls (`promptLlm`) as steps. There's no first-class "call another workflow" step — share logic by extracting it into `src/lib/` or an action, or expose a workflow as an agent tool (`defineWorkflowTool`) / over HTTP when you want it as its own tracked run.
77
+ - **Agent tools** - Agents can use actions, subagents (`defineSubagentTool`), workflows (`defineWorkflowTool`), and MCP tools as tools.
82
78
 
83
79
  ## Audit & debug (CLI)
84
80
 
85
- Use the CLI against the correct target — do not call HTTP directly.
86
-
87
- **Local** (developing / testing):
81
+ Use the CLI to inspect your deployed project.
88
82
 
89
83
  ```bash
90
- keystroke agent sessions list <agent-key>
91
- keystroke agent sessions get <agent-key> <session-id> --include messages,trace
92
- keystroke workflow run <workflow-key> --input '{}'
93
- keystroke workflow runs list <workflow-key>
94
- keystroke workflow runs get <workflow-key> <run-id> --include steps,trace
84
+ keystroke workflow run <workflow-slug> --input '{}'
85
+ keystroke workflow runs list <workflow-slug>
86
+ keystroke workflow runs get <workflow-slug> <run-id> --include steps,trace
87
+ keystroke agent sessions list <agent-slug>
88
+ keystroke agent sessions get <agent-slug> <session-id> --include messages,trace
95
89
  keystroke app list
96
- ```
97
-
98
- **Cloud** (deployed — `keystroke config use cloud` or after deploy):
99
-
100
- ```bash
101
90
  keystroke trigger list
102
- keystroke trigger url <trigger-key>
103
- keystroke trigger runs list <trigger-key>:<workflow-key>
91
+ keystroke trigger url <trigger-slug>
92
+ keystroke trigger runs list <trigger-slug>:<workflow-slug>
104
93
  ```
105
94
 
106
- Read `src/` first existing agents, workflows, actions, and triggers are your best map of how this project works.
95
+ Read `src/` first; existing agents, workflows, actions, and triggers are your best map of how this project works.
96
+
97
+ ## Skills
107
98
 
108
- ## Skills map
99
+ Whenever you work with your Keystroke project, you should review relevant skills. Skills can be found in `.agents/skills/` and are folders named with the following format: `keystroke-[name]`.
109
100
 
110
101
  | Skill | Load when |
111
102
  | ------------------------------------------------------------ | ---------------------------------- |
112
- | [cli](.agents/skills/keystroke-cli/SKILL.md) | Local vs cloud CLI, config, projects |
103
+ | [cli](.agents/skills/keystroke-cli/SKILL.md) | Deploy, run, inspect; projects & auth |
113
104
  | [deploy](.agents/skills/keystroke-deploy/SKILL.md) | Build, full/filtered deploy, WIP ignore |
114
105
  | [agents](.agents/skills/keystroke-agents/SKILL.md) | Building or debugging agents |
115
106
  | [workflows](.agents/skills/keystroke-workflows/SKILL.md) | Orchestration, action steps |
116
107
  | [actions](.agents/skills/keystroke-actions/SKILL.md) | Shared steps, integration tools |
117
108
  | [triggers](.agents/skills/keystroke-triggers/SKILL.md) | Cron, webhook, poll automation |
118
- | [gateways](.agents/skills/keystroke-gateways/SKILL.md) | Slack / messaging bindings |
109
+ | [channels](.agents/skills/keystroke-channels/SKILL.md) | Slack / external channel bindings |
119
110
  | [skills](.agents/skills/keystroke-skills/SKILL.md) | `src/skills/` playbooks |
120
111
  | [files](.agents/skills/keystroke-files/SKILL.md) | Agent workspace files |
121
112
  | [apps](.agents/skills/keystroke-apps/SKILL.md) | Connectable apps, catalog, connect |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: keystroke-actions
3
- description: Define keystroke actions — workflow steps and agent tools. App-backed actions flow through synced apps (app.action); catalog integrations import from npm packages. Use when authoring src/actions/ or wiring integrations.
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
4
  metadata:
5
5
  keystroke-domain: actions
6
6
  ---
@@ -9,28 +9,54 @@ metadata:
9
9
 
10
10
  One **executable unit** used everywhere: workflow steps, agent tools, and codemode host calls.
11
11
 
12
- Anything that calls an external API **flows through an app** sync the app into `src/apps/` first, connect it, then author with `app.action()`. See [apps skill](.agents/skills/keystroke-apps/SKILL.md).
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
13
 
14
14
  ## Actions are leaf units — never call an action from an action
15
15
 
16
- An action's `run` must **not** call another action (yours or an integration action like `postMessage`). Composition belongs in a **workflow**; an integration action is used directly as a workflow step or agent tool — not wrapped in a custom action.
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
17
 
18
18
  ```ts
19
19
  // ❌ Don't: an action that calls another action
20
- import { postMessage } from "@keystrokehq/slack/actions";
20
+ import { slackSendMessage } from "@keystrokehq/slack/actions";
21
21
  export const notify = defineAction({ slug: "notify",
22
- run: async (input) => postMessage.run({ channel: input.channel, text: input.text }),
22
+ run: async (input) => slackSendMessage.run({ channel: input.channel, markdown_text: input.text }),
23
23
  });
24
24
 
25
25
  // ✅ Do: use the integration action directly as a workflow step
26
26
  async run(input) {
27
- return postMessage.run({ channel: input.channel, text: buildText(input) });
27
+ return slackSendMessage.run({ channel: input.channel, markdown_text: buildText(input) });
28
28
  }
29
29
  ```
30
30
 
31
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
32
 
33
- ## App-backed actions (custom integrations)
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:
34
60
 
35
61
  1. **App first** — create in the dashboard or `keystroke app create`, then `keystroke app sync <slug>` → `src/apps/<name>/app.ts`
36
62
  2. **Connect** — `keystroke connect <slug>` (see [apps skill](.agents/skills/keystroke-apps/SKILL.md))
@@ -51,14 +77,14 @@ export const kwatchListAlerts = kwatch.action({
51
77
  });
52
78
  ```
53
79
 
54
- Do not use bare `defineAction` for external API work the app owns the connection.
80
+ Use an app wrapper (over a standalone credential) when a family of actions should share one connection definition.
55
81
 
56
- ## Pure actions (no app)
82
+ ## Pure actions (no credential)
57
83
 
58
- Use `defineAction` directly only when the step needs no app connection (pure logic, local transforms):
84
+ Use `defineAction` with no `credentials` when the step needs no connection at all (pure logic, local transforms):
59
85
 
60
86
  ```ts
61
- import { defineAction } from "@keystrokehq/action";
87
+ import { defineAction } from "@keystrokehq/keystroke/action";
62
88
  import { z } from "zod";
63
89
 
64
90
  export const triage = defineAction({
@@ -77,7 +103,7 @@ Official integrations ship as npm packages with pre-built actions. Discover with
77
103
 
78
104
  ```ts
79
105
  import { exaSearch } from "@keystrokehq/exa/actions";
80
- import { postMessage } from "@keystrokehq/slack/actions";
106
+ import { slackSendMessage } from "@keystrokehq/slack/actions";
81
107
  ```
82
108
 
83
109
  Detail: [catalog-and-imports.md](references/catalog-and-imports.md).
@@ -98,6 +124,28 @@ export const researchSignup = defineAction({
98
124
  });
99
125
  ```
100
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
+
101
149
  ## Where actions run
102
150
 
103
151
  | Consumer | Usage |
@@ -9,15 +9,44 @@
9
9
 
10
10
  ```ts
11
11
  import { exaSearch, exaAnswer } from "@keystrokehq/exa/actions";
12
- import { postMessage } from "@keystrokehq/slack/actions";
12
+ import { slackSendMessage } from "@keystrokehq/slack/actions";
13
13
  import { googlesuperSendEmail } from "@keystrokehq/googlesuper/actions";
14
14
  ```
15
15
 
16
16
  Catalog packages ship a pre-built app + actions — you do not author `src/apps/` for these.
17
17
 
18
- ## Custom integrations (app-first)
18
+ ## Custom integrations
19
19
 
20
- All custom API work flows through a synced app:
20
+ Two supported paths. Pick based on whether actions share a connection.
21
+
22
+ ### Standalone credential (simplest)
23
+
24
+ Declare a `defineCredential` and consume it from a plain `defineAction`:
25
+
26
+ ```ts
27
+ import { defineAction } from "@keystrokehq/keystroke/action";
28
+ import { defineCredential } from "@keystrokehq/keystroke/credentials";
29
+ import { z } from "zod";
30
+
31
+ const acme = defineCredential({ key: "acme", fields: { apiKey: z.string() } });
32
+
33
+ export const fetchStatus = defineAction({
34
+ slug: "fetch-status",
35
+ input: z.object({}),
36
+ output: z.object({ ok: z.boolean() }),
37
+ credentials: [acme] as const,
38
+ async run(_input, credentials) {
39
+ const { apiKey } = credentials.acme;
40
+ return { ok: true };
41
+ },
42
+ });
43
+ ```
44
+
45
+ Connect it with `keystroke credentials set acme --set apiKey=@env:ACME_API_KEY --scope org`.
46
+
47
+ ### App wrapper (shared connection / synced apps)
48
+
49
+ Use an app when several actions share one connection, or when you've synced a custom/catalog app:
21
50
 
22
51
  1. Create the app (dashboard or `keystroke app create --name ... --field ...`)
23
52
  2. Sync: `keystroke app sync <slug>` → `src/apps/<name>/app.ts`
@@ -14,7 +14,7 @@ Agents are **autonomous LLM runs** with a sandbox, optional skills/files, and **
14
14
  **Integration tools** — import actions from an integration package:
15
15
 
16
16
  ```ts
17
- import { defineAgent } from "@keystrokehq/agent";
17
+ import { defineAgent } from "@keystrokehq/keystroke/agent";
18
18
  import { exaSearch, exaAnswer } from "@keystrokehq/exa/actions";
19
19
 
20
20
  export default defineAgent({
@@ -28,7 +28,8 @@ export default defineAgent({
28
28
  **Skills + files** — static playbooks and docs in the workspace:
29
29
 
30
30
  ```ts
31
- import { defineSandbox } from "@keystrokehq/sandbox";
31
+ import { defineAgent } from "@keystrokehq/keystroke/agent";
32
+ import { defineSandbox } from "@keystrokehq/keystroke/sandbox";
32
33
 
33
34
  defineAgent({
34
35
  slug: "support",
@@ -40,6 +41,46 @@ defineAgent({
40
41
 
41
42
  Import actions from `@keystrokehq/<integration>/actions` (e.g. `@keystrokehq/exa/actions`, `@keystrokehq/googlesuper/actions`).
42
43
 
44
+ ## Built-in capabilities (on by default)
45
+
46
+ Two capabilities are enabled automatically — you don't add them to `tools`:
47
+
48
+ - **Memory** — agents persist memory across sessions by default. Disable with `memory: false`.
49
+ - **Web** — built-in `web_search` / `web_fetch` host tools are available by default. Disable with `web: false`.
50
+
51
+ ```ts
52
+ defineAgent({
53
+ slug: "researcher",
54
+ systemPrompt: "…",
55
+ model: "anthropic/claude-sonnet-4-6",
56
+ memory: false, // opt out of persistent memory
57
+ web: false, // opt out of built-in web tools
58
+ });
59
+ ```
60
+
61
+ Delegate to other agents with subagents (`defineSubagentTool`) — see [tools-mcp-codemode.md](references/tools-mcp-codemode.md).
62
+
63
+ ## Structured output (`outputSchema`)
64
+
65
+ `outputSchema` is a **per-prompt** option, not a `defineAgent` field — the same agent can return free text on one call and a schema-validated object on the next. Pass a Zod schema to `prompt(...)` and read the parsed result from `result.output` (typed from the schema):
66
+
67
+ ```ts
68
+ import { z } from "zod";
69
+ import researcher from "../agents/signup-researcher";
70
+
71
+ const Summary = z.object({ company: z.string(), summary: z.string() });
72
+
73
+ const result = await researcher.prompt({
74
+ message: "Research Acme Corp",
75
+ outputSchema: Summary,
76
+ });
77
+ if (result.error) throw new Error(result.error);
78
+
79
+ const { company, summary } = result.output!; // typed { company: string; summary: string }
80
+ ```
81
+
82
+ Without `outputSchema`, `result.output` is `undefined` and you read the reply from `result.messages`. This is an in-process TypeScript API (workflows, actions, scripts) — structured output is **not** exposed over the HTTP route or `keystroke agent prompt`.
83
+
43
84
  ## Run & audit
44
85
 
45
86
  ```bash
@@ -54,19 +95,20 @@ Follow up in the same session: `--session-id <id>`.
54
95
 
55
96
  | From | How |
56
97
  | --------------- | --------------------------------------------------------- |
57
- | CLI | `keystroke agent prompt {key} --message "…"` |
98
+ | CLI | `keystroke agent prompt {slug} --message "…"` |
58
99
  | Workflow action | `await myAgent.prompt({ message })` inside `defineAction` |
59
- | Gateway | Slack message to a bound agent (see gateways skill) |
100
+ | Channel | Slack message to a bound agent (see channels skill) |
101
+
102
+ The agent's identity field is `slug` — it's also the route id (`POST /agents/{slug}`) and the CLI `<agentId>` argument.
60
103
 
61
104
  ## Workspace
62
105
 
63
- - Skills → `/workspace/agent/skills/{key}/`
64
- - Files from `src/files/{key}/` → `/workspace/agent/`
65
- - Pass `module: import.meta.url` so skills/files resolve in dev without a rebuild
106
+ - Skills → `/workspace/agent/skills/{skill-name}/` (the skill's folder name)
107
+ - Files from `src/files/{slug}/` → `/workspace/agent/` (`{slug}` is the agent slug when `files: true`)
66
108
 
67
109
  ## Next references
68
110
 
69
- - [models.md](references/models.md) — model ids, `.env` keys
111
+ - [models.md](references/models.md) — model ids, platform LLM proxy
70
112
  - [tools-mcp-codemode.md](references/tools-mcp-codemode.md) — actions as tools, MCP, codemode
71
113
  - [workflows-and-testing.md](references/workflows-and-testing.md) — sessions, workflow handoff
72
114
 
@@ -5,21 +5,19 @@ model: "google/gemini-2.5-flash"; // vendor/model-id — any pi-ai or gateway ca
5
5
  thinkingLevel: "high"; // optional — defaults to "medium"; use "none" to disable reasoning
6
6
  ```
7
7
 
8
- Per-prompt override via API: `{ "message": "...", "thinkingLevel": "low" }`.
9
-
10
- **Local dev (direct)** — set the provider key for each vendor you use (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, …). Only models in the pi-ai direct registry resolve without gateway.
8
+ `thinkingLevel` accepts `off`, `minimal`, `low`, `medium`, `high`, `xhigh` (`off` disables reasoning).
11
9
 
12
- **Optional gateway** set `AI_GATEWAY_API_KEY` to route all agents through Vercel AI Gateway with the same model string. Unlocks gateway-only ids (e.g. `moonshotai/kimi-k2`, `deepseek/deepseek-v3`, `zai/glm-4.5`).
10
+ Per-prompt override via API: `{ "message": "...", "thinkingLevel": "low" }`.
13
11
 
14
- **Cloud** hosted workers use the platform LLM proxy automatically; no provider keys in the container.
12
+ Set `model` to any `vendor/model-id` and deploy — the platform routes agents through its managed LLM proxy automatically, so there are **no provider keys to configure**.
15
13
 
16
- | Vendor | Example id | Direct key |
17
- | --------- | ----------------------------- | ------------------- |
18
- | Anthropic | `anthropic/claude-sonnet-4.5` | `ANTHROPIC_API_KEY` |
19
- | OpenAI | `openai/gpt-5.5` | gateway only |
20
- | Google | `google/gemini-3.5-flash` | gateway only |
21
- | DeepSeek | `deepseek/deepseek-v3` | gateway only |
22
- | Moonshot | `moonshotai/kimi-k2.5` | gateway only |
23
- | Zhipu GLM | `zai/glm-4.5` | gateway only |
14
+ | Vendor | Example id |
15
+ | --------- | ----------------------------- |
16
+ | Anthropic | `anthropic/claude-sonnet-4.5` |
17
+ | OpenAI | `openai/gpt-5.5` |
18
+ | Google | `google/gemini-3.5-flash` |
19
+ | DeepSeek | `deepseek/deepseek-v3` |
20
+ | Moonshot | `moonshotai/kimi-k2.5` |
21
+ | Zhipu GLM | `zai/glm-4.5` |
24
22
 
25
23
  After changing model, smoke-test: `keystroke agent prompt <key> --message "Hi"`.
@@ -8,7 +8,7 @@ Most agents use imported integration actions:
8
8
  import { exaSearch, exaAnswer } from "@keystrokehq/exa/actions";
9
9
  import { googlesuperFetchEmails, googlesuperSendEmail } from "@keystrokehq/googlesuper/actions";
10
10
 
11
- tools: [exaSearch, exaAnswer, listEmails, sendEmail],
11
+ tools: [exaSearch, exaAnswer, googlesuperFetchEmails, googlesuperSendEmail],
12
12
  ```
13
13
 
14
14
  See each integration package's `actions` export for available tools.
@@ -22,10 +22,52 @@ tools: [triage],
22
22
 
23
23
  Same action works in workflows and on agents.
24
24
 
25
+ ## Subagents (delegate to another agent)
26
+
27
+ Wrap any agent as a tool with `defineSubagentTool` (from `@keystrokehq/keystroke/agent`) and add it to `tools`. The parent delegates a scoped task to the child agent:
28
+
29
+ ```ts
30
+ import { defineAgent, defineSubagentTool } from "@keystrokehq/keystroke/agent";
31
+ import { z } from "zod";
32
+ import researcher from "./researcher";
33
+
34
+ export default defineAgent({
35
+ slug: "planner",
36
+ systemPrompt: "Plan work. Delegate research to the researcher subagent.",
37
+ model: "anthropic/claude-sonnet-4-6",
38
+ tools: [
39
+ defineSubagentTool({
40
+ agent: researcher,
41
+ name: "research",
42
+ label: "Research a topic",
43
+ parameters: z.object({ message: z.string() }), // default toMessage reads params.message
44
+ }),
45
+ ],
46
+ });
47
+ ```
48
+
25
49
  ## MCP
26
50
 
27
- Import MCP definitions from the integration package (e.g. `exaSearchMcp` from `@keystrokehq/exa/mcp`) and add them to `tools` alongside actions.
51
+ Point an agent at an MCP server with `defineMcp` (from `@keystrokehq/keystroke/agent`) and add the definition to `tools` alongside actions. Each tool the server lists becomes available, prefixed with the server `key` (e.g. `mcp__deepwiki__ask_question`).
52
+
53
+ ```ts
54
+ import { defineAgent, defineMcp } from "@keystrokehq/keystroke/agent";
55
+
56
+ const deepwiki = defineMcp({
57
+ key: "deepwiki",
58
+ transport: { type: "http", url: "https://mcp.deepwiki.com/mcp" },
59
+ });
60
+
61
+ export default defineAgent({
62
+ slug: "researcher",
63
+ systemPrompt: "Use the DeepWiki tools to answer questions about repos.",
64
+ model: "anthropic/claude-sonnet-4-6",
65
+ tools: [deepwiki],
66
+ });
67
+ ```
68
+
69
+ For servers that require auth, declare credentials on the definition.
28
70
 
29
71
  ## Codemode (advanced)
30
72
 
31
- Default sandbox has bash. For batch tool calls, agents can run js-exec scripts that call `await tools['action-key'](args)`. Optional VM runtime via `defineAgent({ mode: 'vm' })`.
73
+ Default sandbox has bash. For batch tool calls, agents can run js-exec scripts that call `await tools['action-slug'](args)` (the tool name is the action's slug; MCP tools keep their `mcp__<key>__<tool>` prefix). Optional VM runtime via `sandbox: defineSandbox({ mode: "vm" })` (from `@keystrokehq/keystroke/sandbox`).
@@ -14,7 +14,7 @@ keystroke agent prompt support --message "Summarize that" --session-id <id>
14
14
  keystroke agent sessions get support <session-id> --include messages,trace
15
15
  ```
16
16
 
17
- Use this when an agent misbehaves or a gateway reply looks wrong.
17
+ Use this when an agent misbehaves or a channel reply looks wrong.
18
18
 
19
19
  ## Agent called from a workflow
20
20