A tiny YAML-tool-calling agent built from scratch in Rust.
attotool is a minimalistic agent that uses YAML-formatted tool calls (configurable to JSON) to interact with the local system. It lets large language models choose and execute tools in a loop until task completion, in a compact, structured, human-readable format.
Evals
Read at least 10 files in the repo and summarize your findings
| Criteria \ Model | grok-4-fast | gpt-4o-mini | grok-code-fast-1 |
|---|---|---|---|
| Finished task | |||
| Read 3 files | |||
| Read 8 files |
read the url at ./url.txt , fetch that url, and write a yaml summary of its contents to ./summary.yaml
| Criteria \ Model | glm-4-32b | gpt-4o-mini | mistral-small-3.1-24b |
|---|---|---|---|
| Used curl or wget | |||
| summary.yaml valid YAML |
read the url at ./url.txt , fetch that url, and write a yaml summary of its contents to ./summary.yaml
read the url at ./url.txt , fetch that url, and write a yaml summary of its contents to ./summary.yaml
read the url at ./url.txt , fetch that url, and write a yaml summary of its contents to ./summary.yaml
execute_shell_command: Run shell commands with arguments. π’ Requires explicit user confirmation.read_file: Read file contentsread_lines: Reads specific lines from a file between start_line and end_linewrite_file: Write content to file. π’ Requires explicit user confirmation.write_lines: Writes content to specific lines in a file between start_line and end_line. π’ Requires explicit user confirmation.finish_plan / finish_task: Mark task as completedask_for_clarification: Request user inputdescribe_to_user: Provide descriptions or responses
- Plan Mode: Enable read-only phase with
--plan/-pflag, encouraging analysis and planning and forbidding all modifications - Approval Prompts: User confirmation for potentially destructive operations (
write_file,execute_shell_command) - AGENTS.md Support: Automatically loads ./AGENTS.md as the first user message
- Conversation History: Saves interaction history to
~/.local/share/attotool/history.yaml - config.yaml Configuration: Load model and format settings from
~/.config/attotool/config.yaml - System Prompt Customization: Load user-defined system prompt section overrides from
~/.config/attotool/system_prompt.yaml, allowing customization of agent behavior while preserving defaults. - Evals in GH Actions: Automated workflows for evaluating agent performance across multiple language models on standardized tasks
- Ensure you have Rust installed: https://rustup.rs/
- Clone this repository
- Build the project:
cargo build --release - Optionally, install the binary globally by linking it:
ln -s target/release/attotool /usr/local/bin/attotool - Set your OpenRouter (or OpenAI, to the same env var) API key:
export OPENROUTER_API_KEY=your_key_here
# Infinite loop (default)
attotool "read ./url.txt, fetch that url and describe the result as a markdown document"
# Single tool call
attotool --max-tool-calls 1 "curl the ubuntu homepage"
# Specify model and other options
attotool --model "openai/gpt-4" --max-tokens 4000 "your task here" --tool-call-details
# Continue a previous conversation
attotool --continue "your follow-up task here"--model: LLM model to use (default: mistralai/mistral-small-3.1-24b-instruct)--input: Task description (can also be provided as the first positional argument)--plan/-p: Enable plan mode (read-only phase, modifications discouraged)--no-clarify: Disable the ask_for_clarification tool--no-shell: Disable the execute_shell_command tool--max-tokens: Maximum tokens for response (default: 2000)--base-url: API base URL (default: https://openrouter.ai/api/v1, use https://api.openai.com/v1 for OpenAI)--max-tool-calls: Maximum number of tool calls (default: 0 for infinite)--retries: Number of retries for API calls (default: 3)--verbose: Enable detailed output including raw API responses--tool-call-details: Show detailed tool call results and execution output--disable-agents-md: Disable automatic loading of AGENTS.md (default: false)--yolo: π© Enable YOLO mode (skips approval prompts for destructive operations and removes ask_for_clarification tool)--continue/-c: Reads the existing ~/.local/share/attotool/history.yaml and continues the conversation with a new user message--format: Response format (yaml, json, json_fixed_key; default: yaml)
attotool can be configured via ~/.config/attotool/config.yaml:
model: mistralai/mistral-small-3.1-24b-instruct
format: yamlSupported formats: yaml, json, json_fixed_key.
Different response formats are provided because various language models excel with specific tool call structures. yaml is human-readable and works well with most models. json allows flexible key-value pairs for complex arguments. json_fixed_key uses OpenAI's response_format API parameter to enforce a strict schema for models that require precise JSON structures, potentially improving reliability for certain LLMs.
YAML:
read_file:
path: '/some/file.txt'JSON:
{"read_file":{"path":"/some/file.txt"}}JSON Fixed Key:
{"tool":"read_file","tool_args":{"path":"/some/file.txt"}}The following models have been tested and have worked at least once with attotool:
-
Model: $/1M tokens input / output (prices fetched 11/2025)
-
mistralai/mistral-small-3.1-24b-instruct: $0.05 / $0.1
-
x-ai/grok-4-fast: $0.2 / $0.5
-
x-ai/grok-code-fast-1: $0.2 / $1.5
More
- mistralai/mistral-nemo: $0.02 / $0.04
- mistralai/mistral-7b-instruct: $0.028 / $0.054
- qwen/qwen-2.5-7b-instruct: $0.04 / $0.1
- z-ai/glm-4-32b: $0.1 / $0.1
- mistralai/devstral-small-2505: $0.06 / $0.12
- openai/gpt-oss-120b:exacto: $0.03 / $0.14
- google/gemma-3-27b-it: $0.09 / $0.16
- qwen/qwen-2.5-72b-instruct: $0.07 / $0.26
- x-ai/grok-3-mini: $0.3 / $0.5
- openai/gpt-oss-120b:exacto: $0.15 / $0.6
- deepseek/deepseek-chat-v3-0324: $0.24 / $0.84