Skip to main content

Customization

Mastra Code is designed as a composable library. The createMastraCode() factory function accepts configuration overrides, and the returned AgentController can drive any frontend, not just the built-in TUI.

Programmatic usage

Import createMastraCode to bootstrap Mastra Code in your own application:

TypeScriptsrc/custom-agent.ts
import { createMastraCode } from 'mastracode'

const { controller, session, mcpManager, authStorage } = await createMastraCode({
  cwd: '/path/to/project',
  initialState: {
    yolo: false,
  },
})

session.subscribe(event => {
  if (event.type === 'message_update') {
    const text = event.message.content
      .filter(p => p.type === 'text')
      .map(p => p.text)
      .join('')
    process.stdout.write(text)
  }
})

await session.sendMessage({ content: 'Explain the auth module' })

createMastraCode boots the controller and returns a ready-to-use session. Subscribe to events and send messages on the session; use the controller to switch modes, configure tools, and manage shared resources.

Custom modes

Override the default Build/Plan/Fast modes by passing a modes array:

TypeScriptsrc/custom-modes.ts
import { createMastraCode } from 'mastracode'
import { Agent } from '@mastra/core/agent'

const reviewAgent = new Agent({
  id: 'review-agent',
  name: 'Review Agent',
  instructions:
    'You are a code review specialist. Analyze code for bugs, security issues, and best practices.',
  model: 'anthropic/claude-sonnet-4-6',
})

const { controller } = await createMastraCode({
  modes: [
    {
      id: 'review',
      name: 'Review',
      default: true,
      defaultModelId: 'anthropic/claude-sonnet-4-6',
      color: '#f59e0b',
      agent: reviewAgent,
    },
    {
      id: 'build',
      name: 'Build',
      defaultModelId: 'anthropic/claude-opus-4-7',
      color: '#7c3aed',
      agent: reviewAgent,
    },
  ],
})

Each mode requires an id and an agent. The name, defaultModelId, and color fields control how the mode appears in the TUI.

Extra tools

Add custom tools to the agent's tool set without replacing the built-in tools:

TypeScriptsrc/custom-tools.ts
import { createMastraCode } from 'mastracode'
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'

const deployTool = createTool({
  id: 'deploy',
  description: 'Deploy the current branch to staging',
  inputSchema: z.object({
    environment: z.enum(['staging', 'production']),
  }),
  execute: async ({ environment }) => {
    return { content: `Deployed to ${environment}` }
  },
})

const { controller } = await createMastraCode({
  extraTools: { deploy: deployTool },
})

Extra tools are merged with the dynamic tool set and are available to the agent in all modes.

Custom subagents

Override the default Explore/Plan/Execute subagents. Each subagent receives its own set of tools, scoping what it can do:

TypeScriptsrc/custom-subagents.ts
import { createMastraCode } from 'mastracode'
import { createTool } from '@mastra/core/tools'

const { controller } = await createMastraCode({
  subagents: [
    {
      id: 'explore',
      name: 'Explore',
      description: 'Read-only codebase exploration',
      instructions:
        'You are an expert code explorer. Use read-only tools to answer questions about the codebase.',
    },
    {
      id: 'test-writer',
      name: 'Test Writer',
      description: 'Write tests for the specified module',
      instructions:
        'You are a test-writing specialist. Generate comprehensive tests for the given module.',
    },
  ],
})

Custom storage

Connect to a remote database instead of the default local SQLite:

TypeScriptsrc/custom-storage.ts
import { createMastraCode } from 'mastracode'

const { controller } = await createMastraCode({
  storage: {
    url: 'libsql://my-db.turso.io',
    authToken: 'my-auth-token',
  },
})

This is equivalent to setting .mastracode/database.json but allows configuration at the code level.

Custom interval handlers

Replace or extend the default background tasks:

TypeScriptsrc/custom-intervals.ts
import { createMastraCode } from 'mastracode'

const { controller } = await createMastraCode({
  intervalHandlers: [
    {
      id: 'sync-config',
      intervalMs: 60_000,
      handler: async () => {
        await syncConfigFromRemote()
      },
    },
  ],
})

Interval handlers run on a fixed interval. They start when controller.init() is called and stop when controller.destroy() is called.

Building a custom TUI

Mastra Code exports the MastraTUI class from mastracode/tui for building custom terminal interfaces. The TUI is driven by the AgentController event system:

TypeScriptsrc/custom-tui.ts
import { createMastraCode } from 'mastracode'
import { MastraTUI } from 'mastracode/tui'

const { controller, mcpManager, hookManager, authStorage } = await createMastraCode()

const tui = new MastraTUI({
  controller,
  hookManager,
  authStorage,
  mcpManager,
  appName: 'My Coding Agent',
  version: '1.0.0',
})

tui.run()

The TUI subscribes to controller events and renders messages, tool calls, approvals, and status information in real time.

Initial state overrides

Control default behavior through initialState:

TypeScriptsrc/custom-state.ts
import { createMastraCode } from 'mastracode'

const { controller } = await createMastraCode({
  initialState: {
    yolo: false,
    thinkingLevel: 'high',
    smartEditing: true,
    notifications: 'system',
    permissionRules: {
      categories: {
        read: 'allow',
        edit: 'ask',
        execute: 'ask',
        mcp: 'deny',
      },
      tools: {},
    },
  },
})

Available state fields

FieldTypeDefaultDescription
yolobooleantrueAuto-approve all tool calls
thinkingLevelstring"off"Extended thinking depth for Anthropic models
smartEditingbooleantrueUse AST-based analysis for code edits
notifications"bell" | "system" | "both" | "off""off"Alert when the TUI needs attention
permissionRulesobjectDefault policiesPer-category and per-tool approval policies
observerModelIdstring"google/gemini-2.5-flash"Model for observational memory observer
reflectorModelIdstring"google/gemini-2.5-flash"Model for observational memory reflector
observationThresholdnumber30000Token count triggering observation pass
reflectionThresholdnumber40000Token count triggering reflection pass