# How to Expose Zod-Validated Actions to the Agent in Agent-Native

> Learn how to expose Zod validated actions to the agent in Agent-Native. Use defineAction with Zod schemas and expose them for agent invocation. Get started now.

- Repository: [Builder.io/agent-native](https://github.com/BuilderIO/agent-native)
- Tags: how-to-guide
- Published: 2026-06-27

---

**To expose Zod actions to the agent in Agent-Native, declare your action using `defineAction`, attach a Zod schema for input validation, and configure the `publicAgent` object with `expose: true`; the framework automatically registers the action in the Agent Action Registry at `/_agent-native/actions` for agent invocation.**

BuilderIO/agent-native treats every server action as a first-class API that can be called by both the UI and the AI agent. When you expose Zod actions to the agent, the framework uses your schema as the single source of truth for validation, auto-generated editor interfaces, and structured tool descriptions. This pattern ensures that agents receive identical type guarantees as your frontend components.

## The Three-Step Exposure Pattern

### Step 1: Declare the Action with defineAction

Every action starts with the `defineAction` helper imported from `@agent-native/core`. This function registers the server-side endpoint and prepares the action for runtime discovery.

```typescript
import { defineAction } from "@agent-native/core"
import { z } from "zod"

export default defineAction({
  name: "provider-api-request",
  description: "Make an arbitrary request to a third-party provider API.",
  // configuration continues...
})

```

### Step 2: Attach the Zod Schema

Supply a `schema` property containing a Zod object definition. Agent-Native uses this schema for runtime input validation and to generate the editor UI in the Studio. The schema becomes the contract that both human users and AI agents must satisfy.

```typescript
schema: z.object({
  provider: z.string().min(1),
  endpoint: z.string().min(1),
  method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
  query: z.record(z.string()).optional(),
  body: z.any().optional(),
}),

```

### Step 3: Configure the publicAgent Block

Add the `publicAgent` configuration object to control agent visibility and permissions. This block determines whether the action appears in the agent's tool surface and what constraints apply.

```typescript
publicAgent: {
  expose: true,        // Makes the action visible to the agent
  readOnly: false,     // false = agent may write (POST/PUT/DELETE)
  requiresAuth: true,  // true = caller must be authenticated
},

```

When `publicAgent.expose` is set to `true`, the action's metadata—including its name, description, Zod schema, and permission flags—is injected into the Agent Action Registry.

## What Happens Under the Hood

During server startup, the runtime walks all registered actions and extracts the Zod schema to build a structured description containing type information, required fields, and defaults. According to the source code in [`packages/core/src/server/action-routes.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/server/action-routes.ts), the framework checks the `publicAgent` flags for each action; if `expose` is enabled, that description is added to the registry served at `/api/_agent-native/action-registry`.

The agent queries this registry when planning workflows. When the agent invokes an exposed action, it calls the endpoint at `/api/_agent-native/actions/<action-id>` with a JSON payload. If the payload fails Zod validation, the server returns a 400 error with a `ZodError` object, which the agent surface translates into a clear validation message.

## Complete Working Example

The following example from [`templates/slides/actions/provider-api-request.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/slides/actions/provider-api-request.ts) (lines 79-100) demonstrates a fully exposed action that allows the agent to make arbitrary HTTP requests to third-party APIs:

```typescript
import { defineAction } from "@agent-native/core"
import { z } from "zod"

export default defineAction({
  name: "provider-api-request",
  description: "Make an arbitrary request to a third-party provider API.",
  
  schema: z.object({
    provider: z.string().min(1),
    endpoint: z.string().min(1),
    method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
    query: z.record(z.string()).optional(),
    body: z.any().optional(),
    headers: z.record(z.string()).optional(),
  }),

  publicAgent: {
    expose: true,
    readOnly: false,
    requiresAuth: true,
  },

  async run({ input, context }) {
    const { provider, endpoint, method, query, body, headers } = input
    // Implementation logic to execute the request...
    return { success: true, data: result }
  },
})

```

For a read-only example, see [`templates/plan/actions/visual-answer.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/plan/actions/visual-answer.ts) (line 117), where `publicAgent: { expose: true, readOnly: true }` allows the agent to retrieve visual plan blocks without mutation permissions.

## Handling Validation Errors

Because the Zod schema serves as the single validation layer, any malformed input is rejected before reaching your business logic. When the agent sends an invalid payload, the response follows this structure:

```json
{
  "error": "ZodError",
  "details": [
    { "path": ["provider"], "message": "String must contain at least 1 character(s)" }
  ]
}

```

The agent surface automatically surfaces these validation messages, allowing the AI to correct its approach without manual intervention. This guarantees that both UI components and agent calls receive identical data integrity protections.

## Summary

- **Register** actions using `defineAction` from `@agent-native/core` to create server-side endpoints.
- **Validate** inputs by supplying a Zod `schema`; this defines the contract for both UI and agent interactions.
- **Expose** actions to the agent by setting `publicAgent: { expose: true }`, with optional `readOnly` and `requiresAuth` flags for fine-grained control.
- **Reference** the implementation in [`packages/core/src/server/action-routes.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/server/action-routes.ts) to understand how the runtime builds the Agent Action Registry from your `publicAgent` metadata.

## Frequently Asked Questions

### What is the Agent Action Registry in agent-native?

The Agent Action Registry is an automatically generated endpoint at `/api/_agent-native/action-registry` that exposes metadata for all actions with `publicAgent.expose: true`. The agent queries this registry to discover available tools, their input schemas, and permission requirements before planning workflow steps.

### Can I expose actions without Zod schemas?

No. Agent-Native requires a Zod schema for any action exposed to the agent. The schema serves as the single source of truth for input validation, type-safe editor generation, and agent tool descriptions. Without it, the framework cannot guarantee data integrity or generate the structured descriptions needed for agent planning.

### How do I restrict an agent to read-only operations?

Set `readOnly: true` inside the `publicAgent` configuration object. According to the source code in [`templates/plan/actions/visual-answer.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/plan/actions/visual-answer.ts), this flag signals to the agent that the action only retrieves data and does not perform mutations, which affects how the agent planner sequences operations and manages state.

### What happens if the agent sends invalid data to an exposed action?

The server validates the payload against your Zod schema before executing the `run` function. If validation fails, the endpoint returns a 400 status with a `ZodError` detailing the specific field violations. The agent receives this feedback and can retry with corrected parameters, ensuring robust error handling without exposing internal server logic.