Configuration
Mastra Code is configured through project-level files, global settings, and environment variables. Configuration files live in .mastracode/ directories at the project and user levels.
Custom configuration directory
When embedding Mastra Code, pass configDir to createMastraCode() to replace the .mastracode directory name:
import { createMastraCode } from 'mastracode'
const mastraCode = await createMastraCode({
configDir: '.acme-code',
})
This changes the project and global locations used for MCP server configuration, hooks, slash commands, agent instructions, skills, and legacy database.json discovery. configDir must be a single directory name; absolute paths, . and .., and names containing / or \ are rejected.
File autocomplete
Mastra Code can search project files and attach a path to your message when you type @ followed by part of a filename:
@setupmatches files such assetup.tsandsetup.py.@src/tuinarrows the search to a directory.@"path with spaces"handles paths that contain spaces.
Use the arrow keys to select a suggestion, then press Tab to insert it. Slash-command autocomplete continues to work when file autocomplete is unavailable.
File suggestions use fd, a file finder that respects .gitignore. Install it with your package manager:
# macOS
brew install fd
# Ubuntu or Debian
sudo apt install fd-find
# Arch Linux
sudo pacman -S fd
On Ubuntu and Debian, the executable is named fdfind. Mastra Code detects both fd and fdfind.
Authentication
Mastra Code supports two authentication methods: API keys (environment variables) and OAuth (provider subscriptions). You can use either or both.
Use /connect to add a provider account or API key. Use /setup to configure authentication and model defaults together.
API keys
Run /connect, select Sign in with an API key, and choose a provider to store a key. You can also set API key environment variables. Mastra Code detects them on startup:
export ANTHROPIC_API_KEY=sk-ant-...
export OPENAI_API_KEY=sk-...
export GOOGLE_API_KEY=...
export DEEPSEEK_API_KEY=...
export CEREBRAS_API_KEY=...
export KIMI_API_KEY=...
Mastra Code uses Mastra's model router, which routes requests to the correct provider based on the model ID and available API keys. No OAuth login is required when using API keys.
Interactive API key prompt
/models switches model packs. Built-in packs keep every mode on one provider. Use /model to override the current mode with another model from that provider. Modified built-in packs are labeled in /models; selecting one highlights the overridden modes and lets you activate its overrides or reset it to the original built-in models. To mix providers, create or edit a custom pack with /models.
/models also configures fallback packs: select a pack and choose Set fallback… from its action menu. When every account serving the active pack's provider is unavailable, either rate-limited or down after retries, the turn hops to the fallback pack's model for that mode. Fallbacks work for built-in and custom packs, and chains are allowed (A → B → C). Cycles are capped at one revisit per cascade (A → B → A), then the error surfaces. Every hop renders a notice in the transcript and is saved in the thread history. After a hop, the thread stays on the landed pack until you switch back with /models. There is no automatic recovery.
When packs define an observational memory model, the same chain also covers observational memory: if the active pack's OM provider is unavailable, the observer and reflector fall back to the next pack's OM model in chain order.
If the selected model needs a provider key, Mastra Code prompts for the key and displays its environment variable name, such as ANTHROPIC_API_KEY.
- Enter a key: The key is stored in
auth.jsonand set in the current process environment. The model becomes available immediately. - Cancel the prompt: Press Escape to keep the current model unchanged.
Cancelling a key prompt in the custom pack editor also keeps the previous model unchanged.
Stored API keys persist across sessions. On the next startup, Mastra Code loads them into the environment automatically. Environment variables always take priority — if you later set a key via export, it overrides the stored value.
OAuth login (optional)
If you have a supported provider account or subscription, run /login to sign in. You can also run /connect and select Sign in with an account.
| Provider | OAuth flow | What you get |
|---|---|---|
| Anthropic | Claude Max subscription | Access to Claude models via your subscription |
| OpenAI | ChatGPT Plus / Codex | Access to OpenAI models via your subscription |
| GitHub Copilot | Device code | Access to models available through your Copilot subscription |
| Kimi For Coding | Device code | Access to Kimi For Coding models via your subscription |
| xAI | Device code | Access to Grok models via your xAI account |
OAuth credentials are stored in auth.json alongside the database in the app data directory. During onboarding, you can skip the OAuth step if you already have API keys configured.
Multiple accounts per provider
You can sign in with more than one account for the same provider — for example, two Claude Max accounts or four Kimi For Coding accounts. Run /login and select a provider you are already signed in to: instead of replacing your credentials, Mastra Code opens the account manager for that provider.
The account manager lists every registered account with its label and marks the active one. Selecting an account opens a submenu for it:
- Set as active — makes it the active account used for new requests (only shown for accounts that aren't active).
- Re-authenticate… — refreshes the account's credentials by signing in again.
- Remove… — deletes the account (after confirmation).
Add another account runs the normal sign-in flow and appends the account, then returns to the manager. The new account is not activated — open its submenu and choose Set as active to switch to it.
Exactly one account per provider is active at a time; the others are kept for rotation and switching. After a successful sign-in you can name the account. ChatGPT and xAI accounts pre-fill the account's email, and GitHub Copilot accounts pre-fill the GitHub login when available. /logout still signs out of the provider entirely, removing every registered account.
Subscription routing by model pack
A model pack can pin a different account for each model. In /models, select a pack, choose Set subscription routing…, select a model, then select an account. The picker previews the effect before you save it.
A selected account is used exclusively for that pack and model. If it cannot serve a request, Mastra Code does not fall back to another subscription on the provider — it moves to the pack's configured fallback chain instead, if one is set. This is what keeps a heavy model from consuming the quota on every subscription you own: pin the heavy model to one account and a lighter model to another, and each subscription's usage is spent only where you intended.
Select Automatic to leave the route unpinned — the model then rotates through the provider's accounts (see below).
Preferences belong to the pack and resolved model. Two packs that use the same model can pin different accounts. When a request hops to a fallback pack, that pack's own subscription routing applies.
Automatic account rotation
For eligible failures on the active account, Mastra Code automatically rotates to the next account in the pool and retries:
- Rate limits and quota exhaustion (HTTP 429, 402, or provider usage-limit errors) rotate immediately.
- Auth failures (HTTP 401/403) first force one token refresh of the current account; if the refreshed token still fails, the pool rotates.
- Server errors and network outages first exhaust the normal transient retry budget; if the provider still can't serve the request, the error surfaces without another account being activated.
Rotation starts on the account the pool is currently on — the account the last rotation left active — and walks the provider's accounts in the order they were added, wrapping once. Each account is tried at most once per request. When every account in the pool has been tried, the error surfaces normally or the request moves to the configured fallback pack. Other errors — malformed requests (HTTP 400 with no provider usage-limit message) and anything unrecognized — never rotate; they surface immediately.
Rotation applies to Automatic routes only. A model pinned to a specific account never rotates to a sibling account; its failures go to the pack's fallback chain.
Rotation and transient retries share one retry budget, so after a rotation the remaining accounts may see fewer transient retries each — the next account is always preferred over further retries on a failing one.
Every switch is shown in the transcript as a one-line notice (for example, Switched Kimi account: Work → Personal (rate limit)) and is persisted in the thread history, so it also appears when you reopen the thread later. When a request starts on an account that isn't the first one in the pool, a Starting on … notice marks that too. When a pinned account can't serve a request, the notice names that account (Pinned Anthropic account unavailable (pool exhausted)) rather than reporting the whole pool as unavailable.
When you select ChatGPT Plus/Pro (Codex Subscription) in /connect or during onboarding, Mastra Code asks how you want to sign in:
- Browser (local callback): opens the browser and waits for the OAuth callback on localhost. This is the default.
- Device code (headless): shows a code to enter at
https://auth.openai.com/codex/device— useful for SSH sessions, remote shells, or environments without a browser.
To preselect the device-code flow (for example in scripts or remote shells where the prompt is inconvenient), set MASTRACODE_OPENAI_CODEX_AUTH_MODE=device before launching Mastra Code:
export MASTRACODE_OPENAI_CODEX_AUTH_MODE=device
Authentication priority for Anthropic
When resolving Anthropic models, Mastra Code checks for credentials in this order:
- Claude Max OAuth (if connected through
/connect) ANTHROPIC_API_KEYenvironment variable or stored API key credential- OAuth login prompt (if nothing else is configured)
To switch from OAuth to API key usage, log out with /logout and set your ANTHROPIC_API_KEY environment variable.
Anthropic OAuth warning
Authenticating with a Claude Max subscription through OAuth is a grey area. Anthropic has reportedly banned users for using Claude max credentials outside of Claude Code, so it may violate Anthropic Terms of Service.
Custom providers and models
Use /custom-providers to add OpenAI-compatible providers. Each provider has a name, base URL, optional API key, and one or more model IDs. Saved models appear in selectors such as /models and /subagents alongside built-in models.
Custom providers are stored in settings.json in the application data directory. API keys saved through this flow are stored locally in plaintext, so use it only on a trusted user account and machine.
Direct shell passthrough
In the interactive TUI, input that starts with ! runs as a direct shell passthrough command:
!pwd
!git status --short
This direct passthrough is separate from the agent's execute_command tool. Tool permissions and agent command execution are not changed by this setting.
By default, Mastra Code keeps the compatibility behavior from earlier versions:
- macOS and Linux:
execa(command, { shell: true }), which behaves like/bin/sh -c. - Windows:
execa(command, { shell: true }), which behaves likecmd.exethrough the platform shell.
Mastra Code does not use $SHELL automatically and does not switch Windows users to PowerShell automatically. Configure a shell only when you want direct ! commands to use a specific command language.
Shell passthrough settings
Set the shell in global settings.json with the shellPassthrough block:
{
"shellPassthrough": {
"mode": "path",
"executable": "/bin/zsh",
"family": "posix"
}
}The mode field accepts:
| Mode | Behavior |
|---|---|
default | Keep the built-in shell: true behavior. |
path | Run the configured executable without loading login or profile files. |
login | Run the configured executable and allow shell startup or profile files when supported. |
If executable is set and mode is omitted, Mastra Code treats the shell as path mode.
The family field accepts:
| Family | Behavior |
|---|---|
posix | Run the executable with -c. In login mode, run it with -l -c. |
cmd | Run cmd.exe with /d /s /c. |
powershell | Run PowerShell or PowerShell Core with an encoded command. |
For common executables, Mastra Code infers family from the executable name. pwsh, pwsh.exe, powershell, and powershell.exe use powershell. cmd and cmd.exe use cmd. Other explicit shells use posix on macOS and Linux. On Windows, set family when the executable is not cmd.exe, powershell.exe, or pwsh.exe.
Environment overrides
Use environment variables to override the persisted shell for the current process:
export MASTRACODE_SHELL=/bin/zsh
export MASTRACODE_SHELL_MODE=path
MASTRACODE_SHELL sets the executable. MASTRACODE_SHELL_MODE accepts default, path, or login. Empty values are ignored.
macOS and Linux examples
Run direct ! commands through zsh without loading startup files:
export MASTRACODE_SHELL=/bin/zsh
export MASTRACODE_SHELL_MODE=path
Opt into a login shell when you need shell startup files:
export MASTRACODE_SHELL=/bin/zsh
export MASTRACODE_SHELL_MODE=login
Login mode can be slower or noisy because startup files can print output, prompt for input, change directories, or run long setup commands.
Windows examples
Use cmd.exe explicitly:
$env:MASTRACODE_SHELL = "cmd.exe"
$env:MASTRACODE_SHELL_MODE = "path"
Use PowerShell Core without loading profiles:
$env:MASTRACODE_SHELL = "pwsh"
$env:MASTRACODE_SHELL_MODE = "path"
Use Windows PowerShell and load profiles:
$env:MASTRACODE_SHELL = "powershell.exe"
$env:MASTRACODE_SHELL_MODE = "login"
PowerShell passthrough uses -EncodedCommand and preserves native command exit codes where practical. It treats cmdlet errors as failures so direct shell commands return a non-zero exit code. In path mode, it also uses -NoProfile. In login mode, it omits -NoProfile so PowerShell profiles can load.
MCP servers
Mastra Code can connect to external MCP servers and make their tools available to the agent. Configure servers in JSON files:
| Priority | Path | Scope |
|---|---|---|
| Highest | .mastracode/mcp.json | Project |
.mcp.json | Project root | |
~/.mastracode/mcp.json | Global | |
.claude/settings.local.json | Project (Claude Code compatible) | |
$CODEX_HOME/config.toml | Global (Codex CLI, opt-in) | |
| Lowest | ~/.claude.json | Global (Claude Code, opt-in) |
Project config overrides global config by server name. Servers that Mastra Code reads from another coding agent are the lowest priority fallback.
Reuse servers from Claude Code and Codex
Mastra Code can read the MCP servers you already configured globally in Claude Code and Codex CLI, so you do not have to copy them into ~/.mastracode/mcp.json. Both sources are off by default. Turn them on in global settings.json with the mcp block:
{
"mcp": {
"claudeCodeGlobal": true,
"codexGlobal": true
}
}| Setting | Default | Reads |
|---|---|---|
claudeCodeGlobal | false | mcpServers in ~/.claude.json |
codexGlobal | false | mcp_servers in $CODEX_HOME/config.toml, or ~/.codex/config.toml when CODEX_HOME is unset |
Mastra Code only reads these files and never writes to them. It reads the top-level mcpServers block in ~/.claude.json, so servers scoped to a project under projects are ignored. From Codex it reads command, args, and env for stdio servers, and url, http_headers, and bearer_token_env_var for remote servers. It skips Codex servers set to enabled = false along with Codex settings that Mastra Code does not support, such as approval and timeout options. A missing or unreadable file is not an error, and any entry Mastra Code cannot use is skipped silently. Set MASTRACODE_DISABLE_MCP to turn off every MCP source, including these.
MCP config format
Mastra Code supports two transport types for MCP servers: stdio (local process) and HTTP (remote server via Streamable HTTP or SSE).
Stdio servers
Launch a local process that communicates via stdin/stdout. Requires a command field. The args and env fields are optional.
{
"mcpServers": {
"my-server": {
"command": "npx",
"args": ["-y", "@my-org/mcp-server"],
"env": {
"API_KEY": "your-key"
}
}
}
}HTTP servers
Connect to a remote MCP server via URL. Requires a url field. The optional headers field lets you pass static headers such as authentication tokens.
{
"mcpServers": {
"remote-api": {
"url": "https://mcp.example.com/sse",
"headers": {
"Authorization": "Bearer your-token"
}
}
}
}HTTP OAuth
HTTP servers can also use OAuth when the server supports MCP authorization. Add an oauth object, optionally with a redirectUrl (it defaults to a stable loopback URL when omitted). Mastra Code stores OAuth client data and tokens in the app data directory.
Mastra Code passes this configuration to @mastra/mcp when connecting. The redirect URL must use HTTPS unless it is a loopback HTTP URL, and it must be handled by a callback endpoint that can complete the OAuth flow for that server.
{
"mcpServers": {
"remote-api": {
"url": "https://mcp.example.com/mcp",
"oauth": {
"redirectUrl": "http://localhost:3000/oauth/callback",
"clientName": "Remote MCP",
"scopes": ["mcp:read", "mcp:write"]
}
}
}
}Use clientId and clientSecret when the MCP server requires a pre-registered OAuth client:
{
"mcpServers": {
"remote-api": {
"url": "https://mcp.example.com/mcp",
"oauth": {
"redirectUrl": "http://localhost:3000/oauth/callback",
"clientId": "your-client-id",
"clientSecret": "your-client-secret"
}
}
}
}Do not commit real clientSecret values to a repository. Prefer a project-local or global config file that is not shared.
Use callbackPort as a shorthand for the redirect URL. It synthesizes http://localhost:<callbackPort>/callback, the convention Claude Code and Codex use, so configs written for those clients (such as the one in Slack's official MCP server docs) work verbatim:
{
"mcpServers": {
"slack": {
"url": "https://mcp.slack.com/mcp",
"oauth": {
"clientId": "1601185624273.8899143856786",
"callbackPort": 3118
}
}
}
}callbackPort and redirectUrl are mutually exclusive. Setting both is a configuration error. Pick a port that is normally free on your machine. When the preferred port is busy, the callback server falls back to the next sequential port, and a provider that only registered the original redirect URL will reject the fallback.
Startup behavior
On startup, Mastra Code connects to all configured servers and reports the status:
MCP: 2 server(s) connected, 15 tool(s)
Invalid or ambiguous entries (for example, specifying both command and url, or providing an invalid URL) are skipped with a reason:
MCP: Skipped "bad-server": Missing required field: "command" (stdio) or "url" (http)
Tools from MCP servers are namespaced as serverName_toolName and appear in the agent's tool list alongside built-in tools. Use /mcp to see the status of all servers, including their transport type and any skipped entries.
To turn servers off without editing configuration files, use /mcp disable <server-name|all>. Disabled servers stay visible in /mcp with a disabled marker, their tools are removed from the agent, and the state persists across restarts for the current project. Re-enable them with /mcp enable <server-name|all> or from the interactive /mcp selector.
Add --global to disable or enable servers across every project instead of just the current one: /mcp disable <server-name|all> --global. Global and project scopes are independent — a server disabled globally stays off until you run /mcp enable <server-name> --global, even if it is enabled in the current project. /mcp disable all --global acts as a kill switch for all MCP servers everywhere.
Hooks
Hooks are user-configured shell commands that run at specific lifecycle events. Use hooks for custom validation, logging, notifications, or integration with external systems.
Hook config format
{
"PreToolUse": [
{
"type": "command",
"command": "node scripts/validate-tool.js",
"matcher": {
"tool_name": "execute_command"
},
"timeout": 5000,
"description": "Validate shell commands before execution"
}
],
"PostToolUse": [
{
"type": "command",
"command": "node scripts/log-tool.js",
"description": "Log tool usage"
}
]
}Hook events
| Event | When it fires | Can block? |
|---|---|---|
PreToolUse | Before the agent tool hook wrapper allows a tool call to execute | Yes |
PostToolUse | After the agent tool hook wrapper observes a completed tool call | No |
Stop | When an agent response ends (complete, aborted, or error) | Yes |
UserPromptSubmit | When the user sends a message | Yes |
SessionStart | When a session begins | No |
SessionEnd | When a session ends | No |
Notification | When the TUI fires a notification | No |
AgentStart | When an agent run begins | No |
AgentEnd | When an agent run ends (complete, aborted, error, or suspended) | No |
PermissionRequest | When a tool, sandbox access request, or plan approval requires user permission | No |
PermissionResult | When a user approves, declines, or dismisses a permission gate | No |
Interrupt | When a running run is aborted by the user, goal judge, or a process signal | No |
SubagentStart | When a subagent begins a delegated task | No |
SubagentEnd | When a subagent finishes its delegated task | No |
SessionStart and SessionEnd also describe the checkout the session is running in. When the project directory is a git worktree, both events include worktree_path, and branch and main_repo_path when git can resolve them. The fields are omitted entirely in a main checkout, so a hook can tell the two apart and provision or tear down per-worktree resources such as a database, a bucket, or a dev server:
{
"session_id": "thread-abc123",
"cwd": "/repos/myapp-worktrees/feature",
"hook_event_name": "SessionEnd",
"worktree_path": "/repos/myapp-worktrees/feature",
"branch": "feature/my-branch",
"main_repo_path": "/repos/myapp"
}
These fire on session boundaries, not on worktree creation and removal. Mastra Code detects the worktree it is started in; it does not create or delete worktrees, so a session that ends is not necessarily a worktree that is going away.
UserPromptSubmit runs before a non-command prompt is sent to the agent. If a hook blocks, the prompt is not sent.
PreToolUse and PostToolUse are emitted by the agent tool hook wrapper around tool execution. Run, permission, interrupt, and subagent events are emitted by the TUI lifecycle dispatcher.
Only PreToolUse, Stop, and UserPromptSubmit can block agent behavior. PostToolUse and the lifecycle dispatcher events are non-blocking signals for logging and integration.
Hook I/O protocol
Hook processes receive a JSON payload on stdin with context about the event:
{
"session_id": "thread-abc123",
"cwd": "/path/to/project",
"hook_event_name": "PreToolUse",
"tool_name": "execute_command",
"tool_input": { "command": "npm test" }
}
During an active agent run, all hook payloads include a run_id that identifies the current run. The same run_id appears on AgentStart, tool hooks, PermissionRequest, PermissionResult, Interrupt, SubagentStart, SubagentEnd, AgentEnd, and Stop for that run, so external integrations can correlate events.
A PermissionRequest payload includes the permission kind and call context. permission_kind can be tool_approval, sandbox_access, or plan_approval. tool_name and tool_input describe the gated tool call when the request comes from a tool approval, sandbox access request, or plan approval. PermissionRequest hooks and the agent-finished Notification hook fire as soon as the TUI receives the event, even while an earlier prompt is still waiting for an answer. The agent_done notification is emitted only for agent_end events with reason complete or no reason. Runs that end aborted or with an error never produce it, and runs that end suspended on a prompt do not either; the suspension's own prompt notification covers them.
{
"session_id": "thread-abc123",
"cwd": "/path/to/project",
"hook_event_name": "PermissionRequest",
"run_id": "run-uuid",
"permission_kind": "tool_approval",
"tool_call_id": "call-1",
"tool_name": "execute_command",
"tool_input": { "command": "rm -rf /" }
}
For blocking events (PreToolUse, Stop, UserPromptSubmit), the hook can respond on stdout with a JSON object:
{
"decision": "block",
"reason": "This command is not allowed"
}
Hook config locations
| Priority | Path | Scope |
|---|---|---|
| Higher | .mastracode/hooks.json | Project (appended after global) |
| Lower | ~/.mastracode/hooks.json | Global (runs first) |
Global hooks run before project hooks. For the same event, all hooks execute in order.
Custom slash commands
Define reusable prompt templates as markdown files. Mastra Code scans these directories for .md files:
| Priority | Path | Scope |
|---|---|---|
| Highest | .mastracode/commands/ | Project |
.claude/commands/ | Project (Claude Code compatible) | |
.opencode/command/ | Project (Opencode compatible) | |
~/.mastracode/commands/ | Global | |
~/.claude/commands/ | Global (Claude Code compatible) | |
| Lowest | ~/.opencode/command/ | Global (Opencode compatible) |
Each command file can include YAML frontmatter with name and description fields:
---
name: review
description: Review the current diff for issues
---
Review my current git diff. Look for bugs, security issues,
and violations of the project's coding standards.The filename (or directory structure) determines the command name. For example, git/commit.md becomes /git:commit. Mastra Code scans nested command directories but ignores directories named node_modules.
Commands support variables like $ARGUMENTS for positional args, @filename for file content injection, and !command for shell command output.
Add goal: true to expose the command as a goal entry point under /goal/<command-name>:
---
description: Triage every open PR
goal: true
---
Review every open PR and continue until each PR has a concise TL;DR.Skills
Skills are structured instruction files that the agent loads automatically based on trigger conditions. They provide domain-specific guidance without manually pasting instructions.
Mastra Code scans these directories for skills:
| Priority | Path | Scope |
|---|---|---|
| Highest | .mastracode/skills/ | Project |
.claude/skills/ | Project (Claude Code compatible) | |
.agents/skills/ | Project (Agent Skills spec compatible) | |
~/.mastracode/skills/ | Global | |
~/.claude/skills/ | Global (Claude Code compatible) | |
| Lowest | ~/.agents/skills/ | Global (Agent Skills spec compatible) |
Each skill is a directory containing a SKILL.md file with instructions and trigger descriptions. Skills installed via symlinks (e.g., from npx skills add) are automatically resolved.
Use /skill/<name> to activate a specific skill in the current conversation:
/skill/release-check
Mastra Code loads the skill instructions and sends them to the agent before the next response.
Set user-invocable: false in SKILL.md frontmatter to hide a skill from /skill/<name> autocomplete, the /skills listing, and direct activation. The agent can still load that skill automatically when relevant.
Add metadata.goal: true to expose a skill as a goal entry point under /goal/<skill-name>:
---
name: release-check
description: Check whether a release is ready
metadata:
goal: true
---
Run the release checks and continue until the release is ready or a human decision is required.Agent instructions
Mastra Code loads project-specific instructions from AGENTS.md or CLAUDE.md files and injects them into the agent's system prompt. This is how you can customize the agent's behavior for your project.
Lookup order
For project instructions (first match wins):
AGENTS.mdorCLAUDE.mdin the project root.claude/AGENTS.mdor.claude/CLAUDE.md.mastracode/AGENTS.mdor.mastracode/CLAUDE.md
For global instructions (first match wins):
~/.claude/AGENTS.mdor~/.claude/CLAUDE.md~/.mastracode/AGENTS.mdor~/.mastracode/CLAUDE.md~/.config/claude/AGENTS.mdor~/.config/claude/CLAUDE.md~/.config/mastracode/AGENTS.mdor~/.config/mastracode/CLAUDE.md
AGENTS.md takes priority over CLAUDE.md when both exist at the same location.
Process memory diagnostics
Enable process memory diagnostics before startup when investigating memory growth in a long-running TUI or headless process:
MASTRACODE_PROFILE=1 mastracode
Allocation profiles can contain prompts, credentials, file contents, and tool arguments. Keep the output directory private, do not upload it as telemetry, delete it after the investigation, and never commit captured profiles.
Control the same process-wide diagnostics instance from the TUI:
/profile status
/profile start
/profile capture
/profile stop
Running /profile without an argument shows the current status. capture writes a Chrome allocation-sampling profile and starts a new sampling epoch; it does not force garbage collection or write a heap snapshot. stop writes a final sample and allocation profile before releasing the profiler.
| Environment variable | Default | Minimum | Description |
|---|---|---|---|
MASTRACODE_PROFILE | Disabled | — | Enable startup profiling with 1, true, yes, or on |
MASTRACODE_PROFILE_DIR | <app-data>/profiles | — | Parent directory for private, per-run output directories |
MASTRACODE_PROFILE_SAMPLE_INTERVAL_MS | 10000 | 1000 | Process and V8 sample interval in milliseconds |
MASTRACODE_PROFILE_CAPTURE_INTERVAL_MS | 300000 | 10000 | Allocation-profile capture interval in milliseconds |
MASTRACODE_PROFILE_ALLOCATION_INTERVAL_BYTES | 524288 | 32768 | V8 allocation-sampling interval in bytes |
Each run writes metadata, process samples, garbage-collection events, and timestamped .heapprofile files to a unique directory. Compare JavaScript heap growth with resident set size (RSS): rising heap usage suggests retained JavaScript objects, while rising RSS with a stable heap can indicate external buffers, native libraries, memory-mapped files, or allocator behavior.
Periodic sampling and profile capture add overhead. Increasing the sample, capture, and allocation intervals reduces that overhead. Completed captures survive later process termination, while an abrupt crash or SIGKILL cannot guarantee a final capture.
Storage
Mastra Code stores threads, messages, state, and observational memory in a database. It uses LibSQL by default with a local file in the operating system's application data directory:
| Platform | Directory |
|---|---|
| macOS | ~/Library/Application Support/mastracode/ |
| Linux | ~/.local/share/mastracode/ |
| Windows | %APPDATA%\mastracode\ |
Credentials and global settings are stored alongside the database. To switch to a remote LibSQL (Turso) or PostgreSQL backend, run /settings and select a storage backend. You'll be prompted for a connection URL.
If a PostgreSQL connection fails on startup, Mastra Code falls back to LibSQL and shows a warning so you can fix the connection via /settings.
Observational memory
Observational memory (OM) uses background agents to maintain a dense log of observations and reflections about the conversation, providing long-term context that persists across sessions.
OM scope
Control whether observations are scoped to individual threads or shared across all threads for a project:
| Scope | Behavior |
|---|---|
thread (default) | Observations are private to each conversation thread |
resource (deprecated) | Observations are shared across all threads for the same project |
resource scope is deprecated and will be removed in a future release because it works much worse than thread scope for prompt caching and agent understanding. See resource scope (deprecated).
Configure the scope through:
MASTRA_OM_SCOPEenvironment variable ("thread"or"resource").mastracode/database.json→omScopefield~/.mastracode/database.json→omScopefield
OM model settings
The observer and reflector models default to google/gemini-2.5-flash. Set them through the /om panel or in the controller state.
Custom model packs can carry an optional memory model (stored as models.memory). When creating or editing a pack in /models, the memory step lets you choose a model or skip it. OM models resolve in this order:
- Explicit observer/reflector overrides from the
/ompanel - The active pack's OM model, followed by the OM models of its fallback packs in chain order
- The standalone OM settings, then the default model
Packs without an OM model keep using your standalone OM configuration unchanged.
OM thresholds
| Threshold | Default | Description |
|---|---|---|
| Observation threshold | 30,000 tokens | Token count that triggers an observation pass |
| Reflection threshold | 40,000 tokens | Token count that triggers a reflection pass |
Color theme
Mastra Code detects your terminal's color scheme and applies a matching dark or light theme. You can override the detected theme with the /theme slash command or the MASTRA_THEME environment variable.
Detection order
MASTRA_THEMEenvironment variable: explicitdarkorlight- Persisted setting from
/themecommand (stored insettings.json) - OSC 11 query: asks your terminal for its actual background color
COLORFGBGenvironment variable (set by some terminals like iTerm2 and Konsole)- Falls back to dark theme
Switching themes
Use the /theme command to change the theme at runtime:
/theme light
/theme dark
/theme auto
Running /theme with no arguments shows the current theme. The choice is persisted across sessions.
macOS sleep prevention
On macOS, Mastra Code runs the built-in caffeinate utility only while the agent is active, then stops it when the run completes, aborts, errors, or the TUI exits. Idle sessions do not keep the machine awake.
Set MASTRACODE_DISABLE_CAFFEINATE=1 before launch to disable this behavior:
MASTRACODE_DISABLE_CAFFEINATE=1 mastracode
Environment variables
| Variable | Description |
|---|---|
MASTRA_DB_URL | LibSQL database URL (e.g., libsql://... or file:./data.db) |
MASTRA_DB_AUTH_TOKEN | Auth token for remote LibSQL database |
MASTRA_DB_PATH | Override the local database file path |
MASTRA_USER_ID | Override the auto-detected user identity |
MASTRA_RESOURCE_ID | Override the auto-detected project resource ID |
MASTRA_OM_SCOPE | Observational memory scope (thread, or deprecated resource) |
DEFAULT_OM_MODEL_ID | Default model for OM observer and reflector |
MASTRA_PLANS_DIR | Override the directory where approved plans are saved (default: app data directory) |
MASTRA_THEME | Color theme override (dark or light) |
MASTRACODE_SHELL | Direct TUI ! shell executable override |
MASTRACODE_SHELL_MODE | Direct TUI ! shell mode (default, path, or login) |
MASTRACODE_DISABLE_CAFFEINATE | Disable active-run sleep prevention on macOS when set to 1 |
MASTRACODE_PROFILE | Enable process memory diagnostics |
MASTRACODE_PROFILE_DIR | Override the diagnostics output directory |
MASTRACODE_PROFILE_SAMPLE_INTERVAL_MS | Override the process and V8 sample interval |
MASTRACODE_PROFILE_CAPTURE_INTERVAL_MS | Override the allocation-profile capture interval |
MASTRACODE_PROFILE_ALLOCATION_INTERVAL_BYTES | Override the V8 allocation-sampling interval |
MASTRACODE_DISPATCH_MAX_IN_FLIGHT | Maximum concurrent Factory background dispatches per replica; invalid or unset values use the default |
KIMI_API_KEY | Kimi For Coding API key |
PARALLEL_API_KEY | Enable Parallel-powered web search and extract tools (selectable as the default web provider in /settings) |
TAVILY_API_KEY | Enable Tavily-powered web search and extract tools |
Resource ID override
Resource IDs determine how threads are grouped. By default, Mastra Code generates one from the Git remote URL or filesystem path. Override it to share threads across repositories or isolate threads within a monorepo:
{
"resourceId": "my-custom-project-id"
}You can also set MASTRA_RESOURCE_ID as an environment variable. Two users who set the same resource ID share threads and observations for that resource.
Telemetry
By default, Mastra Code collects anonymous product analytics about how the TUI is used. Each event includes your OS, Mastra Code version, Node.js version, CPU architecture, and a hostname-derived distinct ID. Tracked events cover session start, prompt submission, thread and model changes, slash command usage, and interactive prompts. Prompt text, message content, file paths, and tool inputs are not collected. You can read the source code to check what's collected.
You can opt out of analytics by setting an environment variable:
MASTRA_TELEMETRY_DISABLED=1
You can also set this when launching Mastra Code:
- npm
- pnpm
- Yarn
- Bun
MASTRA_TELEMETRY_DISABLED=1 npx mastracodeMASTRA_TELEMETRY_DISABLED=1 npx mastracodeMASTRA_TELEMETRY_DISABLED=1 npx mastracodeMASTRA_TELEMETRY_DISABLED=1 npx mastracode