> Discover all available pages from the documentation index: https://mastra.ai/llms.txt

# File-based agents

**Added in:** `@mastra/core@1.48.0`

> **Beta:** This feature is in beta. Breaking changes may occur without a major version bump until the API is stable.

You can define an agent by file convention instead of constructing it in code. Mastra discovers a directory under `src/mastra/agents/<name>/`, assembles an [`Agent`](https://mastra.ai/reference/agents/agent), and registers it on your [`Mastra`](https://mastra.ai/reference/core/mastra-class) instance.

## When to use file-based agents

Use file-based agents when you want one directory per agent, with configuration, instructions, tools, skills, workspace files, and subagents grouped together.

Keep using [`new Agent()`](https://mastra.ai/reference/agents/agent) in code when you need dynamic configuration, programmatic registration, or a shared agent instance across modules. Both approaches can coexist: code-registered agents are always present, and the bundler adds file-based agents when you run through the Mastra CLI.

## Quickstart

Create a directory for the agent and add a `config.ts`. Use `agentConfig` so the partial config is typed while sibling files supply the rest.

```typescript
import { agentConfig } from '@mastra/core/agent'

export default agentConfig({
  model: 'openai/gpt-5.5',
  // instructions omitted -> taken from instructions.md
  // tools omitted -> taken from tools/*.ts
})
```

Add the agent instructions:

```markdown
You are a helpful weather assistant. Answer questions about current conditions and forecasts.
```

Add a tool. The filename becomes the tool key, so this file is exposed as `get_weather`.

```typescript
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'

export default createTool({
  id: 'get_weather',
  description: 'Get the current weather for a city',
  inputSchema: z.object({ city: z.string() }),
  execute: async ({ context }) => ({ city: context.city, tempC: 21 }),
})
```

Your `src/mastra/index.ts` stays the same. The discovered agent is registered automatically when you run the app through `mastra dev` or `mastra build`.

```typescript
import { Mastra } from '@mastra/core'
import { Agent } from '@mastra/core/agent'

const supportAgent = new Agent({
  id: 'support',
  name: 'support',
  instructions: 'You are a support agent.',
  model: 'openai/gpt-5.5',
})

// `support` is registered in code; `weather` is discovered from the filesystem.
export const mastra = new Mastra({
  agents: { support: supportAgent },
})
```

Start the app through the Mastra CLI:

**npm**:

```bash
npx mastra dev
```

**pnpm**:

```bash
pnpm dlx mastra dev
```

**Yarn**:

```bash
yarn dlx mastra dev
```

**Bun**:

```bash
bun x mastra dev
```

## Folder structure

The following table shows the supported file-based agent surface:

| File / directory                        | Maps to                                                                                                                                   |
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `agents/<name>/config.ts`               | Default export merged into the agent config. `id` and `name` default to `<name>`.                                                         |
| `agents/<name>/instructions.md`         | The agent `instructions`. The file contents are inlined into generated code.                                                              |
| `agents/<name>/tools/*.ts`              | Each default-exported [`createTool()`](https://mastra.ai/reference/tools/create-tool). The tool key defaults to the filename.             |
| `agents/<name>/skills/*.ts`             | Each default-exported [`createSkill()`](https://mastra.ai/reference/agents/createSkill), added to the agent `skills`.                     |
| `agents/<name>/skills/<skill>/SKILL.md` | A packaged skill. Frontmatter supplies `name` and `description`, the body is the instructions, and files under `references/` are inlined. |
| `agents/<name>/skills/<skill>.md`       | A flat skill. The filename is the skill name and the body is the instructions.                                                            |
| `agents/<name>/memory.ts`               | Default export: a [`Memory`](https://mastra.ai/reference/memory/memory-class) instance used as the agent `memory`.                        |
| `agents/<name>/workspace.ts`            | Default export: a [`Workspace`](https://mastra.ai/reference/workspace/workspace-class) for the agent.                                     |
| `agents/<name>/workspace/`              | Seed files mirrored into the agent's default workspace at build time.                                                                     |
| `agents/<name>/subagents/<childId>/`    | A declared subagent with the same layout as an agent directory. Wired into the parent as a delegation tool named `<childId>`.             |

Test files named `*.test.ts`, `*.spec.ts`, `*.test.js`, and `*.spec.js` are ignored during tool and skill discovery.

## Add skills

Add skills to a file-based agent by placing them under `agents/<name>/skills/`. Three layouts are supported, and they're inlined into the bundle at build time so the deployed agent doesn't read them from disk at runtime.

- A `.ts` file can default-export `createSkill()`:

  ```typescript
  import { createSkill } from '@mastra/core/skills'

  export default createSkill({
    name: 'forecasting',
    description: 'Use when the user asks about multi-day forecasts.',
    instructions: 'Summarize the forecast day by day and call out precipitation.',
  })
  ```

  > **Note:** Visit [`createSkill()` reference](https://mastra.ai/reference/agents/createSkill) for the full API.

- A packaged `SKILL.md` directory uses frontmatter for the name and description. Files under `references/` are inlined with the skill.

  ```markdown
  ---
  name: severe-weather
  description: Use when conditions include storms, flooding, or other hazards.
  ---

  Lead with the active alert, then give safety guidance.
  ```

- A flat `<skill>.md` file uses the filename as the skill name:

  ```markdown
  Always report temperatures in both Celsius and Fahrenheit.
  ```

Discovered skills merge with any `skills` in `config.ts`. On a name collision, `config.skills` wins and a warning is logged. If `config.skills` is a function, discovered skills are ignored with a warning because they can't be statically merged.

## Add memory

Give a file-based agent [memory](https://mastra.ai/docs/memory/overview) by adding a `memory.ts` that default-exports a [`Memory`](https://mastra.ai/reference/memory/memory-class) instance:

```typescript
import { Memory } from '@mastra/memory'

export default new Memory()
```

The exported instance becomes the agent's `memory`. You can also set `memory` directly in `config.ts`. `config.memory` wins over `memory.ts`, and a warning is logged when both are present. If neither is present, the agent has no memory, which is the default.

## Add a workspace

When a file-based agent is discovered through `mastra dev` or `mastra build`, it gets a default workspace unless `config.workspace` or `workspace.ts` supplies one. The default workspace uses a contained filesystem and shell sandbox rooted at a per-agent `workspace/` directory in the bundle.

To customize it, add a `workspace.ts` that default-exports a [`Workspace`](https://mastra.ai/reference/workspace/workspace-class):

```typescript
import { Workspace, LocalFilesystem, LocalSandbox } from '@mastra/core/workspace'

export default new Workspace({
  name: 'weather-workspace',
  filesystem: new LocalFilesystem({ basePath: './data/weather' }),
  sandbox: new LocalSandbox({ workingDirectory: './data/weather' }),
})
```

You can also set `workspace` directly in `config.ts`. `config.workspace` wins over `workspace.ts`, and `workspace.ts` wins over the default workspace.

### Seed files

Add a `workspace/` directory to ship files with the agent. Mastra mirrors every file under it into the agent's default workspace at build time, so the agent starts with those files on disk:

```text
src/mastra/agents/weather/
  config.ts
  workspace/
    README.md
    data/cities.json
```

Seed files are copied into the bundle next to the running server. Commit the starting files alongside the agent that uses them.

## Add subagents

A file-based agent can declare **subagents**, specialist child agents it can delegate to. Add a `subagents/` directory under the agent, with one directory per subagent. Each subagent directory has the same layout as a top-level agent: `config.ts`, `instructions.md`, `tools/`, `skills/`, `memory.ts`, `workspace.ts`, and `workspace/`.

```text
src/mastra/agents/
  supervisor/
    config.ts
    instructions.md
    subagents/
      researcher/
        config.ts
        instructions.md
        tools/
          search.ts
```

Each subagent is assembled as its own agent and wired into the parent's `agents` map. The agent loop lowers it into a model-visible delegation tool. The tool name is the bare directory name, so the example above exposes `researcher` to the supervisor.

A subagent's `config.ts` must set a non-empty `description`. The description is what the model sees when deciding whether to delegate, so the build fails if it's missing.

```typescript
import { agentConfig } from '@mastra/core/agent'

export default agentConfig({
  model: 'openai/gpt-5.5',
  description: 'Researches a topic and returns cited findings.',
})
```

Subagents are isolated. A subagent inherits nothing from its parent. Its tools, skills, and workspace come only from its own directory, and any absent slot falls back to the same framework defaults as a top-level agent.

Subagents can declare their own `subagents/` directories, nesting up to three levels below the top-level agent. A `subagents/` directory deeper than that is ignored with a warning.

```text
src/mastra/agents/
  supervisor/            # depth 0
    subagents/
      researcher/        # depth 1
        subagents/
          summarizer/    # depth 2
```

Naming rules:

- A subagent id that collides with one of the parent's tool keys is a build error.
- A duplicate subagent id under the same parent is a build error.
- If a subagent id also exists in the parent's `config.agents`, the `config.agents` entry wins and logs a warning.
- If `config.agents` is a function, discovered subagents are ignored with a warning because they can't be statically merged.

## Precedence rules

File-based and code-based agents coexist with deterministic rules:

- **Code wins on name collisions:** If an agent name exists in both code and the filesystem, the code-registered agent is kept and a warning is logged.
- **A folder can hold a code agent:** If `config.ts` exports a configured `new Agent({ id: 'file-based-agent', ... })`, that instance is used as-is. Sibling `instructions.md`, `tools/`, `skills/`, `memory.ts`, `workspace.ts`, and `subagents/` entries are ignored with warnings.
- **Instructions:** Dynamic function instructions in `config.ts` win over `instructions.md`. Otherwise, `instructions.md` wins over a static `instructions` string. If neither is present, the build fails for that agent.
- **Model:** A missing `model` fails the build and names the agent directory.
- **Tools:** Tools from `tools/*.ts` merge with `config.tools`. On a key collision, `config.tools` wins and a warning is logged. If `config.tools` is a function, discovered tools are ignored with a warning.
- **Skills:** Skills from `skills/` merge with `config.skills`. On a name collision, `config.skills` wins and a warning is logged. If `config.skills` is a function, discovered skills are ignored with a warning.
- **Memory:** `config.memory` wins over `memory.ts`, and a warning is logged when both are present. If neither is set, the agent has no memory.
- **Workspace:** `config.workspace` wins over `workspace.ts`, which wins over the default workspace.
- **Subagents:** Subagents from `subagents/` merge with `config.agents`. On an id collision, `config.agents` wins and a warning is logged. A subagent id that collides with a tool key, or a duplicate subagent id, is a build error.

## What happens at build time

File-based agents are discovered by the Mastra **bundler**, the step that runs under `mastra dev` and `mastra build`.

File-based agents are registered only when your app runs through the Mastra CLI. If you import your `mastra` instance directly, `agents/<name>/` directories aren't discovered.

When you consume Mastra as a library, register those agents in code instead of relying on file discovery:

```typescript
import { Mastra } from '@mastra/core'
import { Agent } from '@mastra/core/agent'

const weather = new Agent({
  id: 'weather',
  name: 'weather',
  instructions: 'You are a helpful weather assistant.',
  model: 'openai/gpt-5.5',
})

export const mastra = new Mastra({
  agents: { weather },
})
```

## Related

- [Agents overview](https://mastra.ai/docs/agents/overview)
- [Tools](https://mastra.ai/docs/agents/using-tools)
- [Skills](https://mastra.ai/docs/agents/skills)
- [Memory](https://mastra.ai/docs/memory/overview)
- [Supervisor agents](https://mastra.ai/docs/agents/supervisor-agents)
- [Workspace](https://mastra.ai/docs/workspace/overview)
- [Studio overview](https://mastra.ai/docs/studio/overview)
- [`Agent` reference](https://mastra.ai/reference/agents/agent)
- [`createTool()` reference](https://mastra.ai/reference/tools/create-tool)
- [`createSkill()` reference](https://mastra.ai/reference/agents/createSkill)
- [`Memory` reference](https://mastra.ai/reference/memory/memory-class)
- [`Workspace` reference](https://mastra.ai/reference/workspace/workspace-class)