
Agent Mode gives Memo the ability to use tools — it can read files, search the web, execute shell commands, search memory, and more. The agent operates within a sandboxed environment with a strict permission system.
Agent Mode requires an external provider (OpenAI, Claude, Gemini, etc.) with function-calling support. Local GGUF models do not yet support agent tool calling.
The agent ships with 8 tools, each defined by a JSON Schema:
| Tool | Function | Returns |
|---|---|---|
read_file |
Read a file from disk | File contents as string |
write_file |
Create or overwrite a file | Success/failure status |
list_directory |
List files in a directory | Array of file entries |
web_search |
Perform a web search | Search result snippets |
web_fetch |
Fetch and parse a web page | Page text content |
shell_exec |
Execute a shell command | stdout, stderr, exit code |
memory_search |
Search RAG vector memory | Relevant chunks with similarity |
memory_store |
Store content in RAG memory | Chunk ID and embedding status |
{
"name": "shell_exec",
"description": "Execute a shell command in a sandboxed environment",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The shell command to execute"
},
"working_dir": {
"type": "string",
"description": "Working directory for the command"
}
},
"required": ["command"]
}
}
Six permission policies govern how tools are authorized:
| Policy | Behavior |
|---|---|
| always_allow | Tool executes immediately, no prompt |
| always_deny | Tool is blocked for all invocations |
| ask | User is prompted to approve each invocation |
| rate_limited | Allowed max N times per minute (default 30) |
| sandbox_path | File operations restricted to whitelisted directories |
| command_blacklist | Shell commands matching dangerous patterns are blocked |
23 patterns are blacklisted from shell execution to prevent dangerous operations:
rm -rf /, dd if=, mkfs., :(){ :|:& };:, chmod 777 /,
curl ... | sh, wget ... | bash, sudo, doas, > /dev/sda,
mv / /dev/null, fork bomb patterns, /etc/passwd, /etc/shadow,
eval, exec, system, os.system, subprocess, import os, __import__,
nc -l, /proc/sys/, iptables, shutdown, reboot
File operation tools validate paths against a whitelist:
var allowedPaths = []string{
filepath.Join(homeDir, "Documents"),
filepath.Join(homeDir, "Downloads"),
filepath.Join(homeDir, "Desktop"),
dataDir, // Memo's data directory
tmpDir, // System temp, cleaned periodically
}
func validatePath(requested string) (string, error) {
abs, err := filepath.Abs(requested)
if err != nil {
return "", err
}
for _, allowed := range allowedPaths {
if strings.HasPrefix(abs, allowed) {
return abs, nil
}
}
return "", fmt.Errorf("path not in allowed directories: %s", requested)
}
Tool invocations are rate-limited at 30 requests per minute across all tools. Exceeding the limit triggers a cooldown:
type RateLimiter struct {
mu sync.Mutex
window time.Duration // 1 minute
maxReqs int // 30
counters map[string][]time.Time
}
func (r *RateLimiter) Allow(toolName string) bool {
r.mu.Lock()
defer r.mu.Unlock()
// Sliding window enforcement
cutoff := time.Now().Add(-r.window)
// Filter timestamps within window
// Return false if count >= maxReqs
}
The agent runs in an iterative pipeline with a configurable maximum:
User Query
│
▼
[Iteration 1] LLM decides which tool(s) to call
│
├─▶ Tool A executes ──▶ Result
│
▼
[Iteration 2] LLM receives tool results, decides next step
│
├─▶ Tool B executes ──▶ Result
│
▼
...
│
▼
[Iteration N] LLM synthesizes final response
│
▼
User receives answer with audit trail
| Parameter | Default | Maximum |
|---|---|---|
| Max iterations | 10 | 20 |
| Max tool calls per iteration | 3 | 5 |
| Max total tokens | 32K | 128K |
| Rate limit | 30/min | — |
The pipeline terminates when:
Every agent run produces a complete audit trail showing:
┌─ Agent Run #1274 ─────────────────────────────────┐
│ Model: claude-3.5-sonnet │
│ Started: 2026-07-04 14:23:01 │
│ Iterations: 4 │
│ │
│ [1] web_search("golang sqlite-vec example") │
│ → 3 results (0.8s) │
│ [2] read_file("/home/user/project/store.go") │
│ → 245 lines (0.02s) │
│ [3] shell_exec("go test ./... -run TestSearch") │
│ → FAIL: TestSearch (1.2s) │
│ [4] memory_search("sqlite-vec test failures") │
│ → 2 chunks, similarity 0.89, 0.76 (0.05s) │
│ │
│ Final response generated (4.3s total) │
└────────────────────────────────────────────────────┘
The audit trail is stored in the session and can be reviewed anytime.
Agent mode relies on the external provider's function-calling (tool-use) API:
| Provider | Function Calling Support |
|---|---|
| OpenAI | Native (GPT-4o, GPT-4, O-series) |
| Anthropic Claude | Native (tool_use blocks) |
| Google Gemini | Native (function declaration) |
| Groq | Tool use via compatible models |
| OpenRouter | Depends on routed model |
| xAI Grok | Limited |
| Ollama | No (local models only) |
Agent Mode is unavailable when using local GGUF models. A notification in the chat header will indicate "Agent requires external provider" when a local-only provider is active. Switch to an external provider to enable agent capabilities.