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

# Overview

> The smallest unit agents and workflows run.

An action is a typed function that agents and workflows can reuse. Give it an input schema, an output schema, and a `run` function, then use the same action as an agent tool or as a workflow step.

Use an action for a clear, deterministic capability: look up a customer, post a Slack message, classify a message, create an invoice, or call an internal API.

## Example requests

Ask your coding agent for a single capability. It can turn that request into an action your workflows and agents reuse.

> "Build an action that reviews customer feedback submissions and creates a Linear issue if the feedback is bug related."

> "Create an agent tool that looks up a customer in our database by email and returns their billing plan and recent orders."

## How actions are defined

Actions live in your project code under `src/actions/`. Each file exports a `defineAction()` definition, and the runtime discovers it when you run or deploy the project.

```ts src/actions/triage.ts theme={null}
import { defineAction } from "@meetluno/luno/action";
import { z } from "zod";

export const triage = defineAction({
  slug: "triage",
  name: "Triage",
  description: "Classify an inbound message",
  input: z.object({ message: z.string(), sender: z.string() }),
  output: z.object({ priority: z.enum(["low", "normal", "high", "urgent"]) }),
  run: async (input) => {
    const urgent = /urgent|asap|immediately/i.test(input.message);
    return { priority: urgent ? "urgent" : "normal" } as const;
  },
});
```

The `input` and `output` Zod schemas are validated on every execution: the input is parsed before `run` is called, and the return value is parsed before it is handed back. This keeps an action's contract honest no matter who calls it.

## Configuration reference

`defineAction()` accepts these options. `slug`, `name`, `description`, `input`, `output`, and `run` are required.

| Option | Required | What it does |
| - | - | - |
| `slug` | Yes | Stable identity used for discovery and as the tool name when used as an agent tool |
| `name` | Yes | Human-readable label shown in the platform and used for the agent tool label |
| `description` | Yes | Description shown to the model when the action is an agent tool |
| `input` | Yes | Zod schema for the value passed into `run` |
| `output` | Yes | Zod schema for the value `run` returns |
| `run` | Yes | `async (input, credentials) => output`, the body |
| `credentials` | No | Credentials the action needs at runtime. See [credentials](https://docs.os.meetluno.ai/learn/credentials/overview.md). |
| `needsApproval` | No | As an agent tool, pause the agent until a human approves or denies each call: `true` (anyone who can run the agent) or `{ approvers: ["alice@acme.com"] }`; add `editable: true` to let the approver edit the input before approving. See [human approval](https://docs.os.meetluno.ai/learn/agents/build-agents.md#human-approval). |

The `run` function receives the validated `input` and, when the action declares `credentials`, a resolved `credentials` object. A third argument carries an `AbortSignal` (`{ signal }`) you can pass to long-running work so it cancels cleanly when a run is stopped.

## Actions are leaf units

An action's `run` must **not** call another action. Composition belongs in a [workflow](https://docs.os.meetluno.ai/learn/workflows/build-workflows.md); an existing action is used directly as a workflow step or an agent tool, never wrapped in another action.

```ts theme={null}
// Don't: an action that calls another action
import { postBrief } from "./post-brief";

export const notify = defineAction({
  slug: "notify",
  name: "Notify",
  description: "Posts a brief (do not wrap other actions).",
  input: z.object({ text: z.string() }),
  output: z.object({ ok: z.boolean() }),
  run: async (input) => postBrief.run(input), // throws at runtime
});
```

Calling an action from inside another action throws at runtime. The fix is always to compose in a workflow, where each action is a `.then()` step, or attach the action directly as a tool.

An action **may** call an [agent](https://docs.os.meetluno.ai/learn/agents/overview.md) with `.prompt()`; agents are the one thing an action is allowed to invoke.

```ts src/actions/research-signup.ts theme={null}
import { defineAction } from "@meetluno/luno/action";
import { z } from "zod";
import signupResearcher from "../agents/signup-researcher";

export const researchSignup = defineAction({
  slug: "research-signup",
  name: "Research signup",
  description: "Prompts an agent to research a signup and write a brief.",
  input: z.object({ name: z.string(), email: z.string().email() }),
  output: z.object({ brief: z.string() }),
  run: async (input) => {
    const result = await signupResearcher.prompt({
      message: `Research ${input.name} <${input.email}> and write a short brief.`,
    });
    return { brief: result.text };
  },
});
```

## Where actions run

The same action definition is reused by both consumers; there is no separate "tool" type.

| Consumer | Usage |
| - | - |
| **Workflow** | `.then(myAction)` on a `defineWorkflow()` builder, a durable [step](https://docs.os.meetluno.ai/learn/actions/workflow-steps.md) |
| **Agent** | `tools: [myAction]` on `defineAgent()`, an [agent tool](https://docs.os.meetluno.ai/learn/actions/agent-tools.md) |

## Discovery

Luno OS discovers one action per file under `src/actions/`. Use a default export or a single named export; a file with multiple actions is an error. The discovery key is the action's `slug`, not the filename.

```ts theme={null}
// Both are valid; one action per file
export default defineAction({ slug: "triage", name: "Triage", description: "Classify an inbound message", /* … */ });
export const triage = defineAction({ slug: "triage", name: "Triage", description: "Classify an inbound message", /* … */ });
```

## Next steps

> **[Actions as agent tools](https://docs.os.meetluno.ai/learn/actions/agent-tools.md)**
>
> Let an agent call your actions as tools.

> **[Actions as workflow steps](https://docs.os.meetluno.ai/learn/actions/workflow-steps.md)**
>
> Run actions as durable steps inside a workflow.

> **[Credentials](https://docs.os.meetluno.ai/learn/credentials/overview.md)**
>
> Declare and resolve API keys and OAuth for actions.

> **[Integrations](https://docs.os.meetluno.ai/integrations.md)**
>
> Connect the apps you use.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.