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' && event.event.type === 'text-delta') {
    process.stdout.write(event.event.delta)
  }
})

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