Skip to content

Tools System

Eshan Roy edited this page Aug 2, 2026 · 8 revisions

Tools System

M31 Autonomous (M31A) provides a curated set of tools that the LLM can invoke to interact with the filesystem, run commands, search code, and access the web. Tools are registered on a Dispatcher that handles permissions, rate limiting, and execution.

Architecture

flowchart TD
    LLM[LLM Response<br/>tool_call chunks] --> Engine[workflow/engine.go<br/>consumeStreamWithTools]
    Engine --> Dispatcher[tools/dispatcher.go<br/>Execute ToolCall]
    Dispatcher --> Rate[Rate Limiter<br/>token bucket]
    Dispatcher --> Perm[Permission Check<br/>rules + risk level]
    Dispatcher --> Lookup[Tool Lookup<br/>by name]
    Lookup --> Exec[Tool.Execute<br/>ctx, input]
    Exec --> Result[ToolResult]
    Result --> LLM

    style LLM fill:#e1f5fe
    style Dispatcher fill:#fff3e0
    style Result fill:#e8f5e9
Loading

Built-in Tools

Bash

Source: internal/tools/bash.go

Property Value
Risk Level dangerous
Timeout 30 minutes (configurable per call, max 1800s)
Output Limit 50,000 characters
Schema {command: string, timeout?: integer}

Features:

  • Process group management (SIGINT then SIGKILL after grace period)
  • Non-interactive environment variables (CI=true, DEBIAN_FRONTEND=noninteractive)
  • Stdin closed immediately to prevent hangs
  • Binary output detection (null byte check)
  • Output truncation with [... output truncated] marker
  • Concurrent stdout/stderr reading with per-stream buffers

FileRead

Source: internal/tools/fileread.go

Property Value
Risk Level safe
Max File Size 5 MB

Features:

  • Line offset and limit for partial reads
  • Line number prefix (cat -n format)
  • Long line truncation (>2000 chars)
  • Support for images and PDFs (rendered as attachments)

FileWrite

Source: internal/tools/filewrite.go

Property Value
Risk Level medium

Features:

  • Atomic writes (temp file + rename)
  • Auto-backup before overwrite (configurable, max 10 backups per file)
  • Directory auto-creation for new file paths

Edit

Source: internal/tools/edit.go

Property Value
Risk Level dangerous

Features:

  • Exact string replacement (old_string → new_string)
  • Line-range replacement (start_line + end_line + new_string)
  • Cascading replace: 7 strategies (exact, line-trimmed, whitespace-normalized, indent-normalized, line-skip, fuzzy-anchor)
  • Levenshtein similarity for fuzzy matching
  • replace_all flag for batch replacements
  • LCS-based diff summary generation
  • Same atomic write and backup as FileWrite

Glob

Source: internal/tools/glob.go

Property Value
Risk Level safe
Max Results 1,000 (configurable)

Features:

  • Standard glob patterns (**/*.go, src/**/*.ts)
  • Fallback retry with *.<ext> pattern when no matches
  • Sorted results by modification time
  • Skip directories: node_modules, vendor, .next, dist, build, target, .venv, __pycache__

Grep

Source: internal/tools/grep.go

Property Value
Risk Level safe
Max Results 100 (configurable)
Pattern Length Capped to prevent ReDoS

Features:

  • Ripgrep backend when available, pure-Go fallback otherwise
  • Full regex support with fixed_string mode for literal searches
  • File type filtering (include glob parameter)
  • Context lines (before/after match)
  • Ring buffer streaming mode: O(contextLines) memory when context > 0, O(1) when context = 0
  • ReDoS protection: rejects nested/adjacent quantifier patterns
  • Gitignore-aware file filtering with mtime-based cache
  • Result truncation with count reporting

FileDelete

Source: internal/tools/filedelete.go

Property Value
Risk Level destructive

Features:

  • Auto-backup before deletion
  • Path validation (prevents traversal attacks)

FileMove

Source: internal/tools/filemove.go

Property Value
Risk Level medium

FileList

Source: internal/tools/filelist.go

Property Value
Risk Level safe

CodeMap

Source: internal/tools/codeanalysis/codemap.go

Property Value
Risk Level safe

Features:

  • Project structure mapping
  • Symbol extraction
  • Dependency graph generation

WebFetch

Source: internal/tools/webfetch.go

Property Value
Risk Level medium
Max Redirects 5 (configurable)

Features:

  • HTTP to HTTPS auto-upgrade
  • HTML to markdown conversion
  • SSRF protection (blocks private, loopback, link-local IPs)
  • Custom User-Agent header
  • Content type detection

WebSearch

Source: internal/tools/websearch.go

Property Value
Risk Level safe

Features:

  • SearXNG meta-search engine backend
  • No API key required
  • Configurable instance URL
  • Structured results (title, URL, snippet)

TodoWrite

Source: internal/tools/todo.go

Property Value
Risk Level safe

Features:

  • Task tracking within the session
  • Stored in session directory

TodoRead

Source: internal/tools/todoread.go

Property Value
Risk Level safe
Schema `{status?: "pending"

Features:

  • Reads and parses TODO.md from the session directory
  • Filters items by status (pending, in_progress, completed, cancelled, or all)
  • Returns structured summary with counts per status
  • Thread-safe session ID via atomic.Value
  • Read-only companion to TodoWrite

AskUserQuestion

Source: internal/tools/question.go

Property Value
Risk Level safe

Features:

  • Structured questions with multiple-choice options
  • Per-request response routing (prevents cross-caller mix-ups)
  • Timeout support

Agent

Source: internal/tools/agent.go

Property Value
Risk Level medium

Features:

  • Spawns parallel subagents with isolated worktrees
  • Background execution support
  • See Subagents for details

CodeComplexity

Source: internal/tools/codecomplexity.go

Property Value
Risk Level safe
Schema {skip_dirs?: string[]}

Features:

  • Scans Go source files in the project directory
  • Counts files and lines per package and per file
  • Ranks top packages and files by size
  • Produces a complexity score (low, medium, high)
  • Respects skip directories (configurable, merges with defaults)

See CodeComplexity Tool for detailed usage.

DevServer

Source: internal/tools/devserver.go

Property Value
Risk Level medium
Schema `{action: "start"

Features:

  • Start development servers (e.g., npm run dev, python -m http.server)
  • Stop running servers by ID with process group cleanup
  • List all running servers with uptime and port info
  • Check if a port is accepting connections
  • Cross-platform process management (Unix process groups, Windows taskkill)
  • Auto-cleanup on agent shutdown via StopAll()

HTTPCheck

Source: internal/tools/httpcheck.go

Property Value
Risk Level safe
Timeout 15 seconds per request
Schema {url: string, method?: string, expected_status?: number, expected_content?: string[], not_expected_content?: string[], max_body_bytes?: number}

Features:

  • HTTP requests with configurable method, expected status, and content validation
  • Positive and negative content assertions (expected_content / not_expected_content)
  • Redirect limit (10 max) and configurable body size cap (1MB default)
  • Used during runtime verification phase for smoke testing dev servers

Default Registration

All 19 tools are registered in internal/tools/defaults.go:

func DefaultDispatcher(workDir, backupDir, sessionsDir string, cfg *config.ToolsConfig) (*Dispatcher, error) {
    d := NewDispatcher(cfg)
    d.Register(NewBash(workDir, cfg.BashMaxTimeoutSecs, cfg.AdditionalBlockedCommands, cfg.AdditionalObfuscationPatterns))
    d.Register(NewFileRead(workDir))
    d.Register(NewFileWrite(workDir, backupDir))
    d.Register(NewEdit(workDir, backupDir))
    d.Register(NewTodoWrite(sessionsDir, ""))
    d.Register(NewWebFetch(sessionsDir, false, cfg.WebfetchMaxRetries, cfg.WebfetchRetryDelayMs))
    d.Register(NewWebSearch(""))
    d.Register(NewAskUserQuestion(...))
    d.Register(NewGlob(workDir))
    d.Register(NewGrep(workDir))
    d.Register(NewFileList(workDir))
    d.Register(NewFileDelete(workDir, backupDir))
    d.Register(NewFileMove(workDir))
    d.Register(NewCodeMap(workDir))
    d.Register(NewCodeComplexity(workDir))
    d.Register(NewDevServer(workDir))
    d.Register(NewHTTPCheck())
    // Agent tool registered separately on parent dispatcher
    return d, nil
}

Dispatcher

Source: internal/tools/dispatcher.go

The Dispatcher is the central hub for tool execution. It provides:

Rate Limiting

Token bucket algorithm prevents resource exhaustion from LLMs generating excessive tool calls. Two tiers:

Tier Burst Refill Rate Purpose
General 20 tokens 10/sec Normal tool calls
Dangerous 5 tokens 2/sec Destructive operations

Concurrency Limiting

Semaphore-based concurrency control prevents parallel tool execution overload:

  • General concurrency: max_concurrent (default 8)
  • Per-task concurrency: max_tool_concurrency (default 4)

Batch Approvals

Users can approve all pending and future calls for a tool+risk combo:

batchApprovals map[string]BatchApproval  // key: "toolName:riskLevel"

Output Bounding

OutputStore prevents context window exhaustion by bounding tool output:

  • output_max_lines — Max lines per tool output
  • output_max_bytes — Max bytes per tool output
  • output_retention_days — Days to retain output files

Permission System

Every tool execution passes through ensurePermission():

  1. Batch approval check — Check for existing batch approvals
  2. Rule matching -- Checks tool name and arguments against configured rules
  3. Risk assessment -- Classifies as safe, medium, dangerous, or destructive
  4. Agent defaults -- Per-agent permission profiles
  5. Interactive prompt -- Modal in the TUI (allow / allow always / deny / exit)
  6. Non-interactive fallback -- Blocks dangerous tools in shell mode

Input Normalization

The dispatcher handles two input formats from LLMs:

  • Nested: {"name":"Bash", "params":{"command":"ls"}}
  • Direct: {"name":"Bash", "command":"ls"}

Both are normalized to the same internal ToolInput struct.

Parameter Limit

Input is capped at 1000 parameters per tool call to prevent abuse.

DNS Caching

DNS resolution is cached with configurable TTL (dns_cache_ttl_secs, default 300s) to reduce DNS lookup overhead.

Persistent Permissions

Source: internal/tools/persistent_permissions.go

CWD-aware permission caching persists permission decisions across sessions.

Permission Request/Response Protocol

Communication between the dispatcher and TUI uses channels:

Dispatcher ──(PermissionRequest)──→ TUI modal
Dispatcher ←──(PermissionResponse)── TUI user action

Each request has a monotonically increasing ID (atomic counter) for routing responses to the correct waiter. Per-request channels prevent cross-caller response mix-ups in concurrent scenarios.

Clone this wiki locally