Skip to content

Configuration

Eshan Roy edited this page Jul 5, 2026 · 4 revisions

Configuration

M31 Autonomous (M31A) is configured via a TOML file at ~/.m31a/config.toml. Override the path with the M31A_CONFIG environment variable. Project-level config is m31a.toml in the project root.

Config Loading Layers

Configuration is loaded in 6 layers, each overriding the previous:

  1. Compiled defaultsDefaultConfig() in loader.go
  2. Global TOML~/.m31a/config.toml
  3. Environment variablesOPENROUTER_API_KEY, ZEN_API_KEY, etc.
  4. Project TOMLm31a.toml in project root
  5. Variable substitution${VAR} syntax in string values
  6. ValidationValidationError type for structured error reporting

M31A also auto-loads .env from the current directory (with security checks — skips group/world-writable files).

Full Configuration Reference

# ============================================================================
# Provider Configuration
# ============================================================================
[provider]
default = "openrouter"          # Active provider: "openrouter", "zen", or "nvidia"
auto_fallback = true            # Auto-switch to healthy provider on failure
fallback_priority = ["nvidia", "zen", "openrouter"]  # Ordered fallback list
health_check_timeout_secs = 10  # Per-provider health check timeout
registration_order = ["openrouter", "zen", "nvidia"]  # Provider registration order

[provider.openrouter]
api_key = ""                    # OpenRouter API key (prefer keychain)

[provider.zen]
api_key = ""                    # Zen API key (prefer keychain)

[provider.nvidia]
api_key = ""                    # NVIDIA NIM API key (prefer keychain)

# Custom base URLs for self-hosted or proxied gateways
# openrouter_base_url = ""
# zen_base_url = ""
# nvidia_base_url = ""

# HTTP headers for OpenRouter
# openrouter_referer = "https://github.com/eshanized/M31A"
# openrouter_title = "M31A"

# ============================================================================
# Model Configuration
# ============================================================================
[model]
default = ""                    # Default model ID (empty = prompt at startup)
context_warning_threshold = 0.8 # Warn when context usage exceeds this (0.0-1.0)
show_thinking_by_default = false
auto_collapse_tools = false
auto_arbitrage = false          # Auto-switch to cheapest model per task
arbitrage_threshold = 0.1       # Minimum savings ratio to trigger switch
default_context_length = 128000 # Fallback context length when provider doesn't return one
token_ema_alpha = 0.3          # Token estimator EMA calibration rate

# ============================================================================
# Model Capabilities Configuration
# ============================================================================
[model_capabilities]
# Extra patterns appended to built-in lists (additive, never replaces defaults)
# extra_reasoning_patterns = []
# extra_tool_capable_patterns = []
# extra_completion_only_patterns = []
# extra_non_chat_patterns = []

# Known model capability overrides merged with built-in table
# [model_capabilities.known_capabilities]
# "custom-model" = { context_length = 128000, max_output = 8192, supports_tools = true, supports_reasoning = false }

# ============================================================================
# UI Configuration
# ============================================================================
[ui]
theme = "dark"                  # "dark", "light", or "auto"
compact_mode = false
show_token_usage = false
show_cost_estimate = true
max_iterations = 100            # Max workflow iterations (0 = unlimited)
leader_key = "ctrl+x"           # Leader key for chord shortcuts
leader_timeout_ms = 1000        # Leader key timeout
sidebar_width_threshold = 120   # Min terminal width for sidebar auto-show
discuss_timeout = 300           # Discuss Q&A timeout in seconds
thinking_max_lines = 20         # Max lines for thinking block
permission_modal_width = 60     # Permission modal width in columns
sidebar_width = 42              # Sidebar width in columns
max_message_history = 1000      # Max message history entries
fallback_banner_timeout_secs = 15
default_log_lines = 20
session_list_limit = 20         # Max sessions in resume screen
thinking_opacity = 0.6
frecent_history_size = 100      # Frecent history max entries

# Accessibility
reduced_motion = false          # Reduce animations for accessibility
zen_mode_key = "ctrl+z"         # Key to toggle zen mode

# Layout thresholds
width_ultra_compact = 60        # Ultra-compact layout threshold
width_compact = 80              # Compact layout threshold
width_full = 120                # Full layout threshold

# History limits
max_messages = 2000             # Max message history
max_todo_items = 50             # Max todo items

# Sidebar
sidebar_refresh_secs = 30       # Sidebar refresh interval

# Welcome screen
welcome_two_col_threshold = 100 # Min width for two-column welcome
welcome_card_min_width = 20     # Min card width
welcome_card_max_width = 40     # Max card width

# Logo customization
logo_file = ""                  # Path to custom logo file (empty = embedded ASCII art)
logo_text = ""                  # Inline logo text (takes precedence over logo_file)

# Welcome suggestions
# welcome_suggestions = ["Fix a bug", "Add a feature", "Write tests"]

# Keyboard hints
# keyboard_hints = ["Ctrl+X: Leader key", "/help: Get help"]

# Unicode symbol overrides
# [ui.symbol_overrides]
# check = "✓"
# cross = "✗"
# warning = "⚠"

ascii_fallback = false          # Use ASCII instead of Unicode (for poor Unicode terminals)
theme_file = ""                 # Path to custom theme file

# Toast type overrides
# [ui.toast_type_overrides]
# [ui.toast_type_overrides.success]
# icon = "OK"
# title = "Done"

# Theme and Colors
# accent_color = ""
# custom_background = ""
# border_style = ""

# Typography
# bold_headers = true
# italic_thinking = false
# tab_width = 4

# Layout
# sidebar_position = "right"    # "left" or "right"
# sidebar_auto_show = true
# card_padding = 1
# welcome_screen = true

# Animation
# animation_speed = "normal"    # "fast", "normal", "slow"
# spinner_style = ""
# transition_style = ""
# breathing_effects = false
# logo_animation = true

# Status Bar
# status_bar_style = ""
# status_bar_position = "bottom"
# show_spinner_in_status = true

# Tool Cards
# tool_card_style = ""
# tool_output_max_lines = 20
# syntax_highlight = true

# Toasts
# toast_position = "top-right"
# toast_duration_secs = 10
# toast_max_visible = 3

# ============================================================================
# Permissions Configuration
# ============================================================================
[permissions]
default_mode = "prompt"         # "prompt", "allow", or "deny"
timeout_seconds = 300           # Permission modal timeout

# Permission rules (evaluated in order)
# [[permissions.rules]]
# tool = "Bash"
# pattern = "rm -rf"
# risk_level = "destructive"
# action = "deny"

# [[permissions.rules]]
# tool = "Bash"
# pattern = "go test"
# risk_level = "safe"
# action = "allow"

# Per-agent permission profiles
# [permissions.agents.build]
# default_action = "allow"
# [[permissions.agents.build.rules]]
# tool = "Bash"
# pattern = "go build"
# action = "allow"

# ============================================================================
# Features Configuration
# ============================================================================
[features]
auto_backup = true              # Auto-backup files before edit/write
resume_on_startup = false       # Auto-resume most recent session
workflow_mode = ""              # "auto", "full", "fast", or "direct"
model_cache_ttl_minutes = 5     # Model cache TTL
model_cache_stale_hours = 24    # Stale cache fallback TTL
healthcheck_live_ms = 500       # Health check "live" threshold
healthcheck_slow_ms = 2000      # Health check "slow" threshold
session_id_length = 8           # Session ID length in hex chars
max_recent_models = 10          # Max recent models to remember
session_retention_days = 30     # Session retention period
health_check_timeout_secs = 10  # Health check timeout
rate_limit_backoff_secs = 120   # Rate limit backoff
budget_limit_usd = 0            # Per-session budget limit (0 = unlimited)
metrics_enabled = true          # Enable metrics collection

# Plan phase enhancements
plan_research = true            # Pre-plan research step
plan_check = true               # Plan quality checker + revision loop
plan_check_max_iter = 3         # Max revision iterations
plan_security_gate = true       # Security heuristic gate
plan_coverage_gate = true       # Requirements coverage gate
plan_gap_analysis = true        # Post-plan gap analysis
plan_chunked = true             # Chunked plan generation
plan_chunk_threshold = 10       # Tasks threshold for auto-chunking

# Discuss phase enhancements
discuss_quality_check = true    # Question quality checker
discuss_completeness = true     # Answer completeness check
discuss_follow_ups = true       # Follow-up question generation

# Execute phase enhancements
execute_preflight = true        # Pre-execution validation
execute_quality_gate = true     # Per-task acceptance criteria checks
execute_loop_detect = true      # Tool call loop detection

# Verify + Ship phase enhancements
verify_report = true            # Generate verification report
verify_security = true          # Security file scanning
ship_preflight = true           # Pre-ship checklist
ship_changelog = true           # Changelog generation

# Initialize phase enhancements
init_deep_analysis = true       # Deep project analysis
init_preflight = true           # Environment pre-flight checks

# Intent classification
intent_classification = true    # Pre-classify REPL input for routing
intent_classify_timeout_secs = 25  # Timeout for LLM classification

# Workflow thresholds
max_heal_attempts = 3           # Max healing attempts per phase
max_plan_retries = 3            # Max plan retry attempts
context_truncation_threshold = 0.8  # Context truncation threshold

# Retry policy
retry_max_attempts = 3          # Max retry attempts
retry_base_delay_ms = 1000      # Base delay between retries
retry_max_delay_ms = 30000      # Max delay between retries
retry_backoff_multiplier = 2.0  # Backoff multiplier

# Retry-after
max_retry_after_secs = 300      # Max retry-after header value

# Task runner
max_parallel_tasks = 4          # Max parallel tasks

# Coordinator
coordinator_timeout_secs = 60   # Coordinator timeout

# ============================================================================
# Instructions Configuration
# ============================================================================
[instructions]
enabled = true                  # Enable AGENTS.md discovery
disable_project = false         # Disable project-level AGENTS.md

# ============================================================================
# Ledger Configuration
# ============================================================================
[ledger]
enabled = true                  # Enable cross-session learning ledger
max_entries = 100               # Max ledger entries

# ============================================================================
# Agents Configuration (per-phase model assignment)
# ============================================================================
[agents]
default = ""                    # Global agent default model
initialize = ""                 # Model for Initialize phase
research = ""                   # Model for Research phase
plan = ""                       # Model for Plan phase
execute = ""                    # Model for Execute phase
verify = ""                     # Model for Verify phase
runtime = ""                    # Model for Runtime phase
ship = ""                       # Model for Ship phase
discuss = ""                    # Model for Discuss phase

# Subagent profile overrides
# [agents.profiles]
# [agents.profiles.explore]
# description = "Custom explore agent"
# model = "gpt-4"
# allowed_tools = ["Glob", "Grep", "FileRead"]
# max_turns = 20

# ============================================================================
# Git Configuration
# ============================================================================
[git]
commit_prefix = "feat"          # Default commit prefix
fix_prefix = "fix"              # Prefix for fix commits
ship_prefix = "chore"           # Prefix for ship commits
# user_name = ""                # Git user.name override
# user_email = ""               # Git user.email override

# ============================================================================
# Verify Configuration
# ============================================================================
[verify]
# build_command = ""            # Custom build command (empty = auto-detect)
# test_command = ""             # Custom test command (empty = auto-detect)

# ============================================================================
# Tools Configuration
# ============================================================================
[tools]
max_glob_results = 1000
max_grep_results = 100
bash_kill_grace_secs = 5
max_backups_per_file = 10
webfetch_max_redirects = 5
output_max_lines = 5000         # Max lines per tool output
output_max_bytes = 512000       # Max bytes per tool output
output_retention_days = 7       # Days to retain output files

# Rate limiting (two tiers)
rate_limit_burst = 20           # General rate limit burst
rate_limit_per_sec = 10         # General rate limit per second
dangerous_rate_limit_burst = 5  # Dangerous tool rate limit burst
dangerous_rate_limit_per_sec = 2  # Dangerous tool rate limit per second
max_concurrent = 8              # Max concurrent tool executions

# DNS caching
dns_cache_ttl_secs = 300        # DNS cache TTL

# Edit tool
fuzzy_threshold = 0.7           # Fuzzy match threshold
min_lines_for_fuzzy = 3         # Min lines for fuzzy matching

# Bash
bash_max_timeout_secs = 1800    # Max bash timeout (30 min)

# WebFetch
webfetch_max_retries = 3        # Max WebFetch retries
webfetch_retry_delay_ms = 500   # Retry delay in ms

# Execute phase
max_tool_concurrency = 4        # Max tool concurrency per task
loop_detect_window = 3          # Loop detection window

# Dangerous command extensions (additive to compiled baseline)
# additional_blocked_commands = ["docker rm", "kubectl delete", "terraform destroy"]
# additional_obfuscation_patterns = []

# webfetch_user_agent = ""
# skip_dirs = ["node_modules", "vendor"]
# websearch_base_url = ""       # Custom SearXNG instance URL
# websearch_enabled = true

# ============================================================================
# Compaction Configuration
# ============================================================================
[compaction]
auto = true                     # Enable automatic session compaction
buffer = 20000                  # Tokens reserved before compaction triggers
keep_tokens = 8000              # Tokens of recent history to preserve verbatim
proactive = false               # Trigger compaction before phase transitions
tool_calls_threshold = 50       # Check compaction every N tool calls
phase_transition_pct = 80       # Trigger compaction at this % before phase transition
# summary_template = ""         # Inline summary template override
# summary_template_file = ""    # Path to summary template file

# ============================================================================
# Prompts Configuration
# ============================================================================
[prompts]
# system_prompt_file = ""       # Path to custom system prompt (replaces base.md)
# project_prompt_dir = ""       # Project-level prompt overrides (.m31a/prompts/)
# global_prompt_dir = ""        # Global prompt overrides (~/.m31a/prompts/)

# Per-prompt overrides
# [prompts.overrides]
# "execute-task" = "/path/to/custom-execute.md"
# "plan-phase" = "/path/to/custom-plan.md"

# Per-model template overrides
# [prompts.model_template_overrides]
# "mistral" = "/path/to/mistral.txt"
# "deepseek" = "/path/to/deepseek.txt"

# ============================================================================
# Narrative Configuration
# ============================================================================
[narrative]
# Template overrides: map of NarrativeType to template text
# [narrative.template_overrides]
# "task_complete" = "Done! {description} completed successfully."

# Classification overrides: map of EventType to classification
# Valid values: "narrative", "grouped", "hidden", "expanded"
# [narrative.classification_overrides]
# "tool_call" = "expanded"

# ============================================================================
# Templates Configuration
# ============================================================================
[templates]
# external_dir = ""             # External template directory
# website_framework = "nextjs"  # Website framework: "nextjs", "vue", "svelte", "astro", "html"

# Custom design palettes
# [templates.custom_palettes]
# [templates.custom_palettes.custom]
# primary = "#FF5733"
# secondary = "#33FF57"

# ============================================================================
# Skills Configuration
# ============================================================================
[skills]
enabled = true                  # Enable skill discovery
# sources = []                  # Skill discovery directories

Environment Variables

Variable Description
M31A_CONFIG Override config file path
OPENROUTER_API_KEY OpenRouter API key (alternative to keychain)
ZEN_API_KEY Zen API key (alternative to keychain)
NVIDIA_API_KEY NVIDIA NIM API key (alternative to keychain)
USE_EFIE Enable EFIE code intelligence backend (1 to enable)

Config Hot-Reload

M31A watches the config file for changes using fsnotify with 50ms debounce. When the file changes, the config is reloaded and applied at runtime without restarting. Falls back to 5-second polling when fsnotify is unavailable.

Source: internal/config/loader.go

Project Context Detection

M31A detects project type by scanning for marker files up to 3 parent directories deep (MaxProjectConfigDepth):

Marker File Detected Type
go.mod Go project
package.json Node.js project
Cargo.toml Rust project
pyproject.toml / requirements.txt Python project
Gemfile Ruby project

Source: internal/config/project_context.go

Clone this wiki locally