> ## Documentation Index
> Fetch the complete documentation index at: https://app.keystroke.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent tools

> Let agents call your actions as tools.

An [agent](/learn/agents/overview) decides what to do at runtime. To give it reliable capabilities, you attach [actions](/learn/actions/overview) as tools. Each action becomes a tool the model can call with a typed argument, and Keystroke validates the input, runs the action, and returns the result to the agent.

## Attach an action as a tool

Pass action definitions in the `tools` array of `defineAgent()`. The same action you'd use as a workflow step works here, unchanged.

```ts src/agents/support.ts theme={null}
import { defineAgent } from "@keystrokehq/keystroke/agent";
import { triage } from "../actions/triage";

export default defineAgent({
  slug: "support",
  systemPrompt: "Help customers. Use the triage tool to classify incoming messages.",
  model: "anthropic/claude-sonnet-4.6",
  tools: [triage],
});
```

When the agent calls the tool, Keystroke parses the model's arguments against the action's `input` schema, runs `run`, and returns the `output` as the tool result.

## How an action maps to a tool

The action's metadata becomes the tool the model sees:

| Tool field      | Comes from                                         |
| --------------- | -------------------------------------------------- |
| **Name**        | The action `slug`                                  |
| **Label**       | `name`, falling back to `slug`                     |
| **Description** | `description`, falling back to `name`, then `slug` |
| **Parameters**  | The action `input` Zod schema                      |

Because the model reads `description` to decide when to call a tool, give tool actions a clear, action-oriented `description`. The `output` schema shapes what the agent gets back.

## Design tool actions for the model

A tool action is read by the model, so write it for that audience:

* **Write a clear `description`.** The model uses it to decide *when* to call the tool. Say what it does and when to reach for it, in plain language.
* **Describe each input field.** Add `.describe()` to the fields in the `input` schema. The schema becomes the tool's parameters, so the descriptions tell the model what each argument means.
* **Keep the output lean.** The action's `output` is serialized to JSON and returned to the model as the tool result, so it counts against the context window. Return the fields the agent needs to act on, not entire upstream payloads.

```ts src/actions/lookup-customer.ts theme={null}
export const lookupCustomer = defineAction({
  slug: "lookup-customer",
  description: "Look up a customer by email. Use before answering billing questions.",
  input: z.object({
    email: z.string().email().describe("The customer's email address"),
  }),
  output: z.object({
    plan: z.enum(["free", "pro", "enterprise"]),
    openInvoices: z.number(),
  }),
  run: async (input) => lookup(input.email),
});
```

## Use integration actions as tools

Integration packages export actions you can attach directly; you don't redefine them. Import only the ones the agent should have.

```ts theme={null}
import { defineAgent } from "@keystrokehq/keystroke/agent";
import { slackSendMessage, listMessages } from "@keystrokehq/slack/actions";

export default defineAgent({
  slug: "support",
  systemPrompt: "Answer questions and post replies to Slack when asked.",
  model: "anthropic/claude-sonnet-4.6",
  tools: [listMessages, slackSendMessage],
});
```

Browse the full catalog of [integrations](/integrations) for the actions each one provides.

## Credentials for tool actions

When an action declares `credentials`, Keystroke resolves them before the tool runs; the agent never sees the secret. If an action can resolve credentials at more than one [scope](/learn/credentials/overview) (organization, project, or user), pin the scope with `.scope()` when attaching it:

```ts theme={null}
export default defineAgent({
  slug: "support",
  systemPrompt: "Post replies to Slack on behalf of the requesting user.",
  model: "anthropic/claude-sonnet-4.6",
  tools: [slackSendMessage.scope("user")],
});
```

Without an explicit scope, the resolver tries the project default, then the organization default. See [credentials](/learn/credentials/overview) for how scopes and connections work.

## Beyond actions

Actions are the usual way to give an agent reliable capabilities, but `tools` also accepts other tool types: MCP tools, subagents, and workflows — import them directly into `tools` (no wrappers). See [build agents](/learn/agents/build-agents) for subagents and workflows as tools.

## Next steps

<CardGroup cols={2}>
  <Card title="Actions as workflow steps" href="/learn/actions/workflow-steps">
    Run the same actions as durable steps in a workflow.
  </Card>

  <Card title="Build agents" href="/learn/agents/build-agents">
    Configure tools, models, skills, files, and more.
  </Card>

  <Card title="Credentials" href="/learn/credentials/overview">
    Declare and scope the credentials a tool action needs.
  </Card>

  <Card title="Integrations" href="/integrations">
    Browse built-in integration actions to attach as tools.
  </Card>
</CardGroup>
