Skip to content

Tools System

Eshan Roy edited this page Jun 16, 2026 · 4 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

LLM Response (tool_call chunks)
    │
    ▼
workflow/engine.go → consumeStreamWithTools()
    │
    ▼
tools/dispatcher.go → Execute(ToolCall)
    ├── Rate limiter (token bucket)
    ├── Permission check (rules + risk level)
    ├── Tool lookup (by name)
    └── Tool.Execute(ctx, input)
        │
        ▼
    ToolResult → fed back to LLM

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 medium

Features:

  • Exact string replacement (old_string → new_string)
  • Conflict detection when multiple matches exist
  • allow_multiple flag for batch replacements
  • Instruction-based editing (semantic description of the change)
  • 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)

Features:

  • Full regex support via ripgrep-like semantics
  • File type filtering (include parameter)
  • Context lines (before/after)
  • Output modes: content, files_with_matches, count
  • Multiline matching support
  • 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/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

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

Default Registration

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

func DefaultDispatcher(workDir, backupDir, sessionsDir string, cfg *PermissionsConfig) (*Dispatcher, error) {
    d := NewDispatcher(cfg)
    d.Register(NewBash(workDir))
    d.Register(NewFileRead(workDir))
    d.Register(NewFileWrite(workDir, backupDir))
    d.Register(NewEdit(workDir, backupDir))
    d.Register(NewTodoWrite(sessionsDir, ""))
    d.Register(NewWebFetch(sessionsDir, false))
    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))
    // 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:

  • Burst capacity: ToolRateLimitBurst
  • Refill rate: ToolRateLimitPerSec
  • Background goroutine refills tokens; stopped via Stop() with sync.Once safety

Permission System

Every tool execution passes through ensurePermission():

  1. Rule matching -- Checks tool name and arguments against configured rules
  2. Risk assessment -- Classifies as safe, medium, dangerous, or destructive
  3. Agent defaults -- Per-agent permission profiles
  4. Interactive prompt -- Modal in the TUI (allow / allow always / deny / exit)
  5. 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.

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