Skip to main content

createCodingAgent()

Added in: @mastra/core@1.48.0

createCodingAgent() builds a coding Agent with the essential defaults a coding agent always needs: a local workspace, the task-list signal provider when memory is configured, network-retry error processors, and the goal judge prompt. Supply only model and instructions to get a working agent, or override any default.

The returned value is a standard Agent, so it works anywhere an Agent does: including as the agent passed to an AgentController. The function lives in @mastra/core with no hosted service behind it, and every default it fills in is a primitive you can also configure on new Agent() yourself.

The defaults match the ones Mastra Code runs on. The prompt, modes, and tools that make up that product aren't included: createCodingAgent() sets up only the runtime pieces listed under Defaults.

Usage example
Direct link to Usage example

Pass a model and instructions. createCodingAgent() fills in the workspace and the error processors. The task signal provider is added when memory is configured, and the goal prompt when a goal is configured:

src/mastra/coding-agent.ts
import { createCodingAgent } from '@mastra/core/coding-agent'

const agent = createCodingAgent({
id: 'my-coding-agent',
name: 'My Coding Agent',
model: 'openai/gpt-5',
instructions: 'You are a helpful coding assistant.',
})

const result = await agent.generate('Which test files mention the /health endpoint?')

The agent receives the workspace tools for its resolved workspace, so tools is only needed for capabilities beyond the workspace, such as opening a pull request. Mastra also adds a description of the workspace to the system prompt.

warning

The default workspace runs commands on the host machine with the permissions of your application process. See Workspace for how to swap in an isolated sandbox.

For the behavioral prompt Mastra Code uses, covering repository exploration, edits, commands, and commits, build instructions with buildBasePrompt().

Parameters
Direct link to Parameters

createCodingAgent() accepts every field of AgentConfig plus the fields below. Fields you provide replace the corresponding default, except for signals: the default task signal provider is merged into the providers you pass. See Signals.

model:

MastraLanguageModel | DynamicArgument<MastraLanguageModel>
The language model the agent uses. Passed straight through to Agent.

instructions:

string | DynamicArgument<string>
System instructions for the agent. Passed straight through to Agent.

tools?:

ToolsInput | DynamicArgument<ToolsInput>
Tools available to the agent. Passed straight through to Agent.

workspace?:

AnyWorkspace | undefined
The workspace backing the agent. When the key is omitted, a default local workspace is built. When set explicitly to undefined, no default is built. Opt out this way when the workspace is wired elsewhere, for example at the AgentController level.

basePath?:

string
= process.cwd()
Base path for the default workspace built when workspace is omitted.

signals?:

SignalProvider[]
Signal providers for the agent. A TaskSignalProvider is added only when memory is configured, and it is merged into the providers you pass rather than replacing them. Without memory, the agent gets exactly the providers you pass, or none.

errorProcessors?:

Processor[]
Error processors for the agent. When omitted, defaults to unknown stream-error retries with specialized ECONNRESET and bad-request policies, plus PrefillErrorHandler and ProviderHistoryCompat.

goal?:

AgentGoalConfig
Goal configuration. When provided without a prompt, the prompt defaults to DEFAULT_GOAL_JUDGE_PROMPT.

Returns
Direct link to Returns

agent:

Agent
A coding agent with the resolved workspace, signals, error processors, and goal applied.

Defaults
Direct link to Defaults

A default is only filled in when you don't provide the corresponding field. signals is the exception: the task signal provider is appended to the providers you pass.

FieldDefault when omitted
workspaceA Workspace backed by LocalFilesystem and LocalSandbox rooted at the base path.
signalsA TaskSignalProvider, added only when memory is configured.
errorProcessorsUnknown stream-error retries with specialized ECONNRESET and bad-request policies, plus PrefillErrorHandler and ProviderHistoryCompat.
goal.promptDEFAULT_GOAL_JUDGE_PROMPT (only when a goal is configured).

Nothing else is filled in. There's no default model, instructions, tools, memory, storage, or input and output processors.

Each default has an explicit opt-out:

DefaultHow to opt out
Workspaceworkspace: undefined
Task trackingDon't configure memory on the agent
Error processorserrorProcessors: []
Goal judge promptOmit goal, or pass your own goal.prompt

Workspace
Direct link to Workspace

When the workspace key is omitted, a local workspace rooted at basePath (default process.cwd()) is built:

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

new Workspace({
filesystem: new LocalFilesystem({ basePath }),
sandbox: new LocalSandbox({ workingDirectory: basePath }),
})

To keep that shape but work in a different directory, pass basePath:

import { createCodingAgent } from '@mastra/core/coding-agent'

const agent = createCodingAgent({
id: 'my-coding-agent',
name: 'My Coding Agent',
model: 'openai/gpt-5',
instructions: 'You are a helpful coding assistant.',
basePath: '/srv/checkouts/my-app',
})

Pass a workspace to build the backends yourself. Here the agent reads the whole repository while commands run inside one package. A remote sandbox takes the place of LocalSandbox in the same slot, see Sandbox for the available backends and isolation options:

import { createCodingAgent } from '@mastra/core/coding-agent'
import { LocalFilesystem, LocalSandbox, Workspace } from '@mastra/core/workspace'

const agent = createCodingAgent({
id: 'my-coding-agent',
name: 'My Coding Agent',
model: 'openai/gpt-5',
instructions: 'You are a helpful coding assistant.',
workspace: new Workspace({
filesystem: new LocalFilesystem({ basePath: '/srv/checkouts/my-app' }),
sandbox: new LocalSandbox({ workingDirectory: '/srv/checkouts/my-app/packages/api' }),
}),
})

To opt out (for example, when the workspace is injected at the AgentController level), pass workspace: undefined explicitly. An omitted key builds the default, an explicit undefined builds nothing:

import { createCodingAgent } from '@mastra/core/coding-agent'

const agent = createCodingAgent({
id: 'my-coding-agent',
name: 'My Coding Agent',
model: 'openai/gpt-5',
instructions: 'You are a helpful coding assistant.',
workspace: undefined, // opt out of the default workspace
})

Signals
Direct link to Signals

TaskSignalProvider adds the task_write, task_update, task_complete, and task_check task tools and persists the list in thread state, which gives the agent a durable plan across a multi-step request:

import { createCodingAgent } from '@mastra/core/coding-agent'
import { Memory } from '@mastra/memory'

const agent = createCodingAgent({
id: 'my-coding-agent',
name: 'My Coding Agent',
model: 'openai/gpt-5',
instructions: 'Plan multi-step work with the task tools, then carry it out.',
memory: new Memory(),
})

The provider needs a memory-backed thread, so it's only added when memory is configured. With memory configured, the provider is merged into any signals you pass, which keeps task tracking from being dropped by custom providers. Passing signals: [] alongside memory still yields the task provider. To run a memory-backed agent with no task tracking, configure the agent with new Agent() instead. Before @mastra/core@1.49.0, the provider was always added, which failed in memoryless contexts.

TaskSignalProvider takes no constructor arguments, so customizing this default means choosing which other providers the agent gets:

import { createCodingAgent } from '@mastra/core/coding-agent'
import { WebhookSignalProvider } from '@mastra/core/signals'
import { Memory } from '@mastra/memory'

const agent = createCodingAgent({
id: 'my-coding-agent',
name: 'My Coding Agent',
model: 'openai/gpt-5',
instructions: 'You are a helpful coding assistant.',
memory: new Memory(),
signals: [
new WebhookSignalProvider({
extractResourceId: payload => (payload as { repository: string }).repository,
}),
],
})

That agent gets the webhook provider and the task provider.

Error processors
Direct link to Error processors

The default StreamErrorRetryProcessor applies these retry policies:

  • Unknown errors left unmatched by provider metadata or a specific matcher retry up to twice with a 3000ms delay. Known authorization failures surface immediately.
  • Network resets (ECONNRESET / socket hang up) retry up to twice with exponential backoff (1000ms * 2^retryCount, capped at 30000ms).
  • Bad-request errors retry once after 2000ms.

Specific network-reset and bad-request policies take precedence over the unknown-error policy. Passing errorProcessors replaces the default processor stack. PrefillErrorHandler and ProviderHistoryCompat are also included for provider compatibility: both repair errors caused by the shape of the message history, such as a provider rejecting a conversation that ends with an assistant message.

Retries happen inside the generate() or stream() call that hit the error, so a recovered failure is invisible to your code. When the retries run out, the error surfaces the way any model error does: generate() rejects and stream() emits an error chunk. generate() and stream() also accept errorProcessors per call, which replaces the agent's stack for that request. See Processors for maxProcessorRetries, the retry budget these processors share.

Goal
Direct link to Goal

No goal is configured by default. When you pass a goal without a prompt, DEFAULT_GOAL_JUDGE_PROMPT is used. The goal config carries the judge and the run budget, while the objective itself is per thread and set with setObjective():

import { createCodingAgent } from '@mastra/core/coding-agent'
import { Memory } from '@mastra/memory'

const agent = createCodingAgent({
id: 'my-coding-agent',
name: 'My Coding Agent',
model: 'openai/gpt-5',
instructions: 'You are a helpful coding assistant.',
memory: new Memory(),
goal: {
judge: 'openai/gpt-5-mini',
maxRuns: 50,
},
})

const threadId = 'thread-1'
const resourceId = 'user-1'

await agent.setObjective('Get the test suite passing', { threadId, resourceId })

Goals require a storage backend and a memory-backed thread. Without a resolved judge, the goal step is a no-op.