local models · sbx · tiny language models · tools · 10 min read

One day, one feature: Mini Me's built-in tools and declared tools

How Mini Me runs tools for a local model: the agent loop, the built-in tools led by bash, and how to declare your own tools in a few lines of YAML.

K
k33gOct 23, 2026 · 10 min
One day, one feature: Mini Me's built-in tools and declared tools

A language model can do only one thing: produce text (data). It does not read your files, does not run commands and does not go on the web. And yet, when you ask Mini Me (mm) "what's in this folder?", the answer gives the real files of the folder. Between the model and your machine, there are the tools.

The principle: the model asks, Mini Me runs

A tool, seen from the model, is an entry in a catalogue (of tools): a name (for example: bash), a description in natural language ("runs a shell command") and a schema of its parameters (for example: command, a string). Mini Me sends this information with every request, next to the conversation.

The model then has two ways to answer:

  • it writes text, and the turn is over;
  • it writes a tool call: the name of a tool and its arguments in JSON, for example bash with {"command": "ls -la"}.

The model runs nothing by itself. It is Mini Me that reads the call, runs the command, collects its output and sends it back to the model as a new message of the conversation.

The model reads this result and decides what comes next: another tool call, or the final answer.

The mini-me agent loop
The mini-me agent loop

That's the whole agent loop. A turn can chain several round trips (read a file, change it, run the tests, read the error again ...), within the limit of maxTurns (10 by default, a setting you can change in the agent's configuration file).

Mini Me comes from the start with a set of ready-to-use tools: the built-in tools.

What is a built-in tool?

A built-in tool is a tool written in Go inside mm itself, in the internal/tools package. It ships with the binary: there is nothing to install, nothing to write and no server to start. You turn it on or off with a simple setting in the agent's configuration file, for example bashTool or editTools, and many of them are on by default.

The other tools, which we can call custom tools, are the ones you add yourself, like declared tools, wasm tools and finally MCP tools.

For the model, there is no difference: all tools arrive as the same information we saw above (a name, a description, a schema) and go through the same loop. What sets a built-in tool apart is that it is designed with mm and for mm: it is tuned to take into account the constraints that come with local models.

Focus: bash, the tool everything starts from

If an agent could have only one tool, it would be bash. With a shell, the model can list a folder (ls), read a file (cat), search the code (grep), run the tests (go test ./...), compile, query git ... It is also bash that skills use: a skill is a procedure in Markdown that tells the model which commands to run, and bash is what runs them.

A single parameter

Seen from the model, the tool could not be simpler:

FieldTypeDescription
commandstringThe shell command to run.

All the flexibility is in this string: pipes, redirections, chaining with &&. That's its strength but also its risk.

Keep it, watch it, or do without it

bash is Mini Me's most powerful tool, so it is the one you set up with the most care:

  • **yolo: false**: every command is submitted to you before it runs.
  • **bashTool: false** removes the shell: the model can still read and change files with read_file, write_file and edit_file, but never runs a command again.

Let's move on to the list of the available built-in tools.

The built-in tools

ToolWhat it is forTurned on byAsks for permission (yolo: false)
bashRun a shell command (bash -c) and read its output, stdout and stderr merged; 30 s at most by default.bashTool: true (default)Yes
read_fileRead a file, whole or a range of lines, with line numbers when asked.editTools: true (default)No
write_fileCreate or fully replace a file; returns the diff.editTools: true (default)Yes
edit_fileChange a file with exact replacements (old → new), forgiving differences in spaces and indentation; returns the diff.editTools: true (default)Yes
read_skillRead a skill, a procedure in Markdown, picked from the catalogue listed in the tool's description.At least one skill in skillsDirNo
planKeep a plan of tasks (create, update, move to the next one) during multi-step work; mm shows the progress.planTool: true (default)Yes for the actions that change the plan
ask_userAsk the user one to four questions (choice, multiple choice, free text, yes/no) and wait for the answers.askUserTool: true (default)No: asking a question changes nothing
unload_modelFree a model from the server's memory (llmman, Ollama, llama-server in router mode).unloadModels: true (default)No
lspNavigate the code with a language server: definition, references, hover, symbols, diagnostics, rename.At least one server of lsp.servers found on the PATHOnly for rename
fetch_contentDownload a web page and convert it to Markdown (robots.txt respected), or save it to a file. The only built-in tool that goes on the network.fetchContentTool: trueOnly when it saves a file
ask_agentHand a task to another mm agent (another model, another prompt) and get its answer back.At least one agent in mmConfigsYes
save_answerSave to a new file an answer the model just gave, without having it write the answer again.saveAnswerTool: trueYes
search_docsSearch passages in documentation folders (Markdown, AsciiDoc...), ranked by relevance.docSearch.autoSearchDocs: trueNo
search_memoryFind what was said in earlier sessions.sessions.enabled and sessions.autoSearchMemory: trueNo

The details of each tool (parameters, error messages, display) are in the tools reference.

Turning your tools on / off

The settings go in the agent's configuration file.

An agent that changes the code freely but has no shell:

yaml
bashTool: false
editTools: true
yolo: true

An agent that has a shell but asks you before every command, and that can read the web:

yaml
bashTool: true
fetchContentTool: true
yolo: false

Important: fewer tools turned on also means a shorter list for the model to read: with a small model, declaring only what the agent needs is a good habit, it helps the model "stay focused" and spot tool calls better.

Beyond the built-in tools

The built-in tools cover the everyday work of a coding agent. For the rest, Mini Me offers three ways to add more, all going through the same loop:

  • declared tools: a tools: entry in the agent file turns one of your commands into a typed tool, with no shell in between;
  • wasm tools: the same entry with a WebAssembly module, run by Mini Me;
  • MCP servers, to plug in existing tools (GitHub, Context7, Wikipedia...).

Wasm tools and MCP servers will be the topic of an upcoming post.

Declared tools

A "declared" tool turns a command you run by hand into a tool the model recognises, and sees on every turn just like bash or read_file.

Why not let a model use bash? Because with a small model, a "declared" tool can be more reliable and faster: the model does not have to work out how to use a bash command, it has the information "right away": the name, the description and the parameters of the tool. On a small series of measurements (three actions, 30 runs per model), Mellum2 12B succeeded 15 times out of 30 with a skill and bash, and 30 times out of 30 with the declared tool, in 1.3 s on average instead of 4.5 s. But let's not generalise: it depends on the use case, the model, the system instructions... In short, you have to spend your time testing and experimenting.

How to declare a tool

You add a tools: block to the agent's configuration file, with one entry per tool:

  • name: the name the model calls, after the action (say_hello, calculate...); it cannot reuse the name of a built-in tool;
  • description: what the tool does and when to use it. It is all the model has to choose, so it must be precise;
  • parameters: one parameter per argument, with its type (string, number, integer or boolean), a description, and when needed an enum (the only accepted values), required: false and a default;
  • command: the command, as a list: the program first, then one entry per argument, with {{parameter}} where the value goes.

For the rest, a declared tool behaves like the built-in tools: it asks for permission with yolo: false, answers in text even when it fails, and goes through the loop detector.

Example 1: saying hello

The "hello world" of declared tools: one parameter, and the echo command.

yaml
tools:
  - name: say_hello
    description: Greet someone by name.
    parameters:
      name: { type: string, description: "The name of the person to greet" }
    command: ["echo", "👋 Hello, {{name}}!"]
text
> Say hello to Philippe.
🧰 say_hello: echo 👋 Hello, Philippe!
   │ 👋 Hello, Philippe!

A placeholder can sit in the middle of a text: the value is inserted into a single entry of the command.

Example 2: what time it is

The shortest possible tool, with no parameter at all. It gives the model a piece of information it cannot know by itself.

yaml
  - name: current_time
    description: Give the current date and time of this computer.
    command: ["date"]
text
> What time is it?
🧰 current_time: date
   │ Thu Oct 22 22:45:21 CEST 2026

Example 3: counting the lines of a file

A file as a parameter, passed to wc -l.

yaml
  - name: count_lines
    description: Count the lines of a file.
    parameters:
      file: { type: string, description: "The file to count, e.g. notes.txt" }
    command: ["wc", "-l", "{{file}}"]
text
> How many lines in team.txt?
🧰 count_lines: wc -l team.txt
   │ 3 team.txt

Example 4: a calculator

Typed parameters (integer) and an enum that limits the operation to four values.

yaml
  - name: calculate
    description: Compute an operation on two whole numbers.
    parameters:
      a:  { type: integer }
      op: { type: string, enum: ["+", "-", "*", "/"] }
      b:  { type: integer }
    command: ["expr", "{{a}}", "{{op}}", "{{b}}"]
text
> What is 12 times 7?
🧰 calculate: expr 12 * 7
   │ 84

The source code of the complete configuration file is here: agent.yaml. Copy it into a folder and run mm tui:

Greetings
Greetings
Current time
Current time
Count lines
Count lines
Calculate
Calculate

Going further

Tools are powerful, but use them with care.

K

Written by

k33g

Keep reading

Hello Mini Me: an agent born while preparing a talk for Devoxx

Meet Mini Me, a coding agent born from a Devoxx talk on the agent loop, built for small local models with guardrails against loops and hallucinations.

Oct 3, 2026
Hello Mini Me: an agent born while preparing a talk for Devoxx

Mini Me release v0.3.0

What is new in Mini Me v0.3.0, the Devoxx Belgium release: approval mode, agents calling agents, request traces, JSON answers, AGENTS.md and an sbx kit.

Oct 10, 2026
Mini Me release v0.3.0

One day, one feature: Connect Mini Me to the world with MCP

Give a Mini Me agent MCP superpowers with a few lines of YAML: query Wikipedia, then add Context7 so a small local model can search up-to-date library docs.

Oct 27, 2026
One day, one feature: Connect Mini Me to the world with MCP

Responses

0 Comments

No comments yet. Be the first to comment!

Related reading

From other blogs

A mini code agent with Docker Agent + Docker Model Runner - Part 1

k33g_org's Blog