How Facio Picks the Right Tool for the Job: The Decision Framework Behind Tool Selection in AI Agents
A Facio agent has 25+ native tools plus dynamic MCP extensions. The tool surface is large by design — composability requires coverage — but the size creates a real problem: agents can pick the wrong tool.
An agent that uses exec("cat file.txt") instead of read_file(path="file.txt") wastes iterations and burns tokens. An agent that uses read_file on a 50,000-line log file instead of grep produces output that overwhelms the context. An agent that uses web_search when it should have used recall misses the curated, private context for a question that the user already answered last week.
Picking the right tool for the task is one of the most common failure modes in agentic systems. Facio's approach is to turn tool selection into a decision the agent reasons about explicitly — with a clear framework, observable rules, and learned patterns. Here's how the framework works and why tool selection is a learnable skill.
Why Tool Selection Is Hard
Tool selection feels like a solved problem in software engineering. A developer writes code, the function names are explicit, and the compiler tells you when you got it wrong. For an AI agent, the function names are presented as options in context. The "compiler" doesn't reject wrong choices — the agent gets an error from the runtime, by which point it has already spent an iteration and possibly derailed its plan.
The difficulty compounds with the number of tools:
- More tools = more ambiguity. When the agent has 5 tools, the choice is usually obvious. When it has 30+, the boundaries blur.
read_filevs.exec("head file")vs.grepvs.web_fetchfor "read this content" — multiple tools can technically produce the result. - Composability creates choices. A research task can use
web_search + web_fetch + read_file + greporweb_search + browser_navigate + read_file. The agent has to pick the right combination. - Tool overlap is intentional. Facio's tools overlap on purpose —
execcan do almost anything the file tools can do,web_fetchcan read articles thatbrowser_navigatecan also read. The overlap gives the agent flexibility, but it also creates decision points. - Context shifts the right answer. A
read_filecall is fine for a 1KB config file and disastrous for a 100MB log file. The same tool, different contexts, different right answers.
The result: tool selection is a per-call decision the agent has to make correctly. Get it wrong, and the agent pays in iterations, in token cost, in context window bloat, or in error responses that derail its plan.
The Decision Framework
Facio's approach to tool selection is structured around four decision dimensions. The agent reasons about each one explicitly before picking a tool:
Dimension 1: What Kind of Action Is This?
The first decision is whether the task is perception (read), action (modify), or coordination (configure).
TASK: "Find the database password in the .env file"
TYPE: Perception (read-only)
→ File tools, not exec or message
TASK: "Update the database password"
TYPE: Action (modify)
→ File editing tools, possibly credential store
TASK: "Schedule a daily backup of the database"
TYPE: Coordination (configure)
→ cron or heartbeat tools
The agent identifies the action type before picking the tool. Most mistakes happen when the agent picks an action tool for a perception task (exec("cat") instead of read_file) or a coordination tool for an action task (manage_channel to update a file).
Dimension 2: What's the Data Source?
The second decision is where the data lives. Different sources have different tools.
| Data source | Right tool family |
|---|---|
| Local files in the workspace | read_file, write_file, edit_file, glob, grep |
| Files outside the workspace | exec (with appropriate safety) |
| Live web pages | web_fetch (clean content) or browser_navigate (interactive) |
| Search-required web | web_search (then web_fetch) |
| Past conversations and memory | recall |
| System logs and audit trail | read_logs |
| Database or external API | exec with appropriate commands, or MCP server |
| Conversation partner | message, ask_approval, ask_form, ask_selection |
The agent identifies the source. Local files use file tools. Web pages use web tools. Memory uses recall. Logs use read_logs. The wrong source mapping produces the wrong tool choice.
Dimension 3: What's the Operation's Specific Shape?
Within each tool family, there are multiple tools for different operations. The agent picks the one that matches the specific shape.
For files:
"Read this file" → read_file(path=...)
"Find files by name" → glob(pattern=...)
"Find files by content" → grep(pattern=..., path=...)
"Replace text in a file" → edit_file(path=..., old_text=..., new_text=...)
"Replace one occurrence globally" → patch_file(path=..., old_text=..., new_text=..., replace_all=true)
"Create a new file" → write_file(path=..., content=...)
"Modify a Jupyter notebook cell" → notebook_edit(path=..., cell_index=..., edit_mode=...)
"Append to a file" → edit_file or write_file depending on existing content
For web:
"Find sources on a topic" → web_search(query=...)
"Read a known URL's content" → web_fetch(url=...)
"Interact with a website (login, click)" → browser_navigate + browser_click
"Download a file from a URL" → exec with curl/wget
For coordination:
"Run a one-time task later" → cron with `at`
"Run a recurring task" → cron with `cron_expr` or `every_seconds`
"Run a task at regular intervals as part of the agent's loop" → HEARTBEAT.md
"Add a new MCP server" → manage_mcp(action="add", ...)
"Add a new model" → switch_model(model=...)
"Configure credentials" → manage_credentials or credential store
The specific-shape decision is where most tool-selection errors happen. The agent has the right family but picks the wrong tool. edit_file for a new file (should be write_file). glob for content search (should be grep). web_search for a known URL (should be web_fetch).
Dimension 4: What Are the Constraints?
The final decision accounts for operational constraints:
- Cost.
switch_modelto a cheap model for simple iterations. Avoidweb_searchwhen the answer is already in memory. - Latency.
read_fileis faster thanexec("head ...").web_fetchis faster thanbrowser_navigate. Pick the faster tool when latency matters. - Output size.
grepfor specific patterns,read_filewith offset/limit for large files,execwith output redirect for huge outputs. Don't pull 50MB into the context window. - Security/Approval. Destructive operations need HITL approval first. The agent doesn't pick
exec("rm -rf")without thinking about whether it's appropriate. - Context budget. If the iteration budget is low, prefer tools that produce concise output. Avoid tools that produce verbose results when summary is enough.
The constraint dimension is where the agent's efficiency shows up. The agent that picks grep for "find all references to the auth flow" instead of read_file on every related file is using one iteration instead of twenty. The constraint-aware choice is the production-quality choice.
The Decision Tree
Putting the four dimensions together, the agent follows a decision tree:
1. What kind of action?
├── Perception → continue to step 2
├── Action → continue to step 2
└── Coordination → continue to step 2
2. Where is the data?
├── Local workspace files → File tools
├── Live web → Web tools
├── Past memory → recall
├── Logs → read_logs
├── External system → exec or MCP
└── Conversation partner → message or HITL tools
3. What's the specific operation?
├── File family: read_file | write_file | edit_file | glob | grep | notebook_edit
├── Web family: web_search | web_fetch | browser_navigate | browser_click
├── Coordination family: cron | heartbeat | manage_mcp | switch_model | manage_credentials
└── Memory family: recall | read_logs
4. What are the constraints?
├── Cost → prefer cheap model, avoid redundant queries
├── Latency → prefer direct over indirect
├── Output size → prefer targeted over comprehensive
├── Security → prefer non-destructive, escalate if destructive
└── Context budget → prefer concise over verbose
5. Pick the tool that wins on all four dimensions.
The tree is simple but explicit. The agent that reasons through the tree before picking a tool makes fewer mistakes than the agent that picks by pattern matching.
Common Tool-Selection Mistakes
Despite the framework, certain mistakes happen repeatedly. Knowing them helps the agent (and the developer) avoid them.
Mistake 1: exec("cat file.txt") Instead of read_file
# Wrong:
exec(command="cat projects/config.json")
# 10,000 character output dumped into context
# Right:
read_file(path="projects/config.json")
# Clean, structured, no shell parsing
exec is for invoking the system, not for reading files. The file tools are optimized for file access. The wrong choice burns tokens on shell overhead and produces messier output.
Mistake 2: read_file on a Huge File
# Wrong:
read_file(path="huge-server.log")
# 50MB of output overwhelms the context
# Right:
exec(command="grep ERROR huge-server.log | head -50")
# 50 lines of relevant content
read_file is for files the agent can reasonably fit in context. For larger files, the agent uses exec with grep/head/tail/awk to extract the relevant slice.
Mistake 3: web_search for a Known URL
# Wrong:
web_search(query="GitHub status page")
# Returns search results, agent fetches the actual page
# Right:
web_fetch(url="https://www.githubstatus.com/")
# Direct content extraction
web_search is for finding sources. When the source is already known (from memory, from the user, from a previous search), the agent skips search and uses web_fetch directly.
Mistake 4: web_fetch for Interactive Pages
# Wrong:
web_fetch(url="https://app.example.com/dashboard")
# Fetches login wall, no actual content
# Right:
browser_navigate(url="https://app.example.com/dashboard")
browser_type(...) for login
browser_snapshot() for content
web_fetch is for static, public content. For pages behind authentication, requiring JavaScript, or needing interaction, the agent uses the browser tools.
Mistake 5: recall for Current Information
# Wrong:
recall(query="current weather in Berlin")
# Returns memory of past weather, not current
# Right:
web_search(query="weather Berlin now")
# Or use the weather MCP server
recall is for the agent's memory and history. Current, external information comes from web_search or specialized MCP servers.
Mistake 6: message for Interactive Workflows
# Wrong:
message(content="Please approve: deploy to production?")
# Sends a text message, human can't approve in-place
# Right:
ask_approval(title="Deploy to production?", options=[...])
# Renders an interactive approval card
message is for delivering information. ask_approval, ask_form, and ask_selection are for interactive workflows where the human needs to make a decision or provide structured input.
Mistake 7: write_file for Partial Edits
# Wrong:
# Read entire file
read_file(path="config.yaml")
# Modify in memory
config["new_field"] = "value"
# Write entire file back
write_file(path="config.yaml", content=full_content)
# Right:
edit_file(path="config.yaml", old_text="existing_field: value", new_text="existing_field: value\nnew_field: value")
edit_file is for surgical changes. write_file rewrites the entire file, which can lose content (comments, formatting) the agent didn't see.
How Tool Selection Improves Over Time
The framework is a starting point. The agent's tool selection improves through three feedback mechanisms:
1. Runtime Error Patterns
When the agent picks the wrong tool, the runtime returns a structured error. The agent learns from the error and adjusts the next pick:
exec(command="cat huge.log")
# Error: output exceeded 10,000 character truncation limit
# Next session:
exec(command="head -100 huge.log")
# Clean output, no truncation
The error pattern is captured. Future sessions use the right tool from the start.
2. Inline Learning
When the user corrects the agent's tool choice, the correction is captured in MEMORY.md:
edit_file(MEMORY.md)
# Old: "## Tool Notes"
# New: "## Tool Notes
# - For large log files, use `exec` with `grep`/`head`/`tail`, not `read_file`
# - For interactive web pages, use browser_navigate + browser_click, not web_fetch"
The lesson is durable. Future sessions load the guidance as passive context and apply it automatically.
3. Reflection-Curated Heuristics
Periodically, Reflection consolidates the agent's accumulated tool-selection wisdom:
## Tool Selection Heuristics (curated 2026-06-15)
- File content search → grep, not read_file + scan
- Known URL → web_fetch directly, skip web_search
- Interactive page → browser_*, not web_fetch
- Recent conversation context → recall before web_search
- Memory file modifications → edit_file with surgical old_text/new_text, not write_file
The heuristics are distilled from many sessions into the most useful patterns. The agent loads them on every session and applies them consistently.
When the Framework Breaks Down
The framework isn't infallible. Some situations require judgment:
Ambiguous data sources. "Find the latest commit" — is it in git (exec), in a file (read_file), or in a log (read_logs)? The agent reasons about which is most likely and tries the most direct first.
Tools with overlapping capabilities. exec("head file.txt") vs. read_file(path="file.txt", limit=10) — both can read the first 10 lines. The agent picks based on the broader context (do I need other shell features? am I in a non-shell workflow?).
New situations without prior pattern. A novel task may not have a clear framework match. The agent reasons by analogy, picks the closest tool, observes the result, and learns from the outcome.
Constraints conflict. The fastest tool is the most expensive. The cheapest tool is the slowest. The agent weighs the tradeoffs and picks the best balance for the current context.
These judgment calls are where agent quality varies. The framework gives structure; the agent's reasoning fills the gaps. The Reflection process captures the successful judgments as heuristics. The agent gets better at tool selection over time.
Bottom Line
Tool selection is a per-call decision the agent has to make correctly. Get it wrong, and the agent pays in iterations, in tokens, in error responses, in context window bloat. Get it right, and the agent's work is efficient and accurate.
Facio's tool selection framework gives the agent a structured way to reason about tool choice: identify the action type, locate the data source, pick the specific operation, account for constraints. The four-dimension decision tree isn't a heuristic — it's an explicit reasoning process the agent runs before every tool call.
The framework doesn't eliminate mistakes. It makes mistakes visible, learnable, and improvable. The agent that makes a tool-selection error gets structured feedback, captures the lesson via inline learning, and consolidates the wisdom via Reflection. The next session starts with the lesson in context.
Because tool selection isn't a one-time design decision. It's an ongoing operational skill. The agent that gets better at it over time is the agent that gets more efficient, more accurate, and more valuable with every passing session.
See the tool selection documentation for the full decision tree, common mistake patterns, and the inline learning workflow for tool-selection lessons.