Skip to content

The AI's Tools

When a capable model works on your project, it does not just emit code. It calls tools: reading a file, searching the project, editing one function, running a syntax check, looking something up on the web. Each call appears as a short line in the chat while it works. This page lists every tool, what it does, and when it is available.

The full list

Tool What it does Available
list_files The project's file tree with line counts. Skips build output, archives and virtual environments. Multi-turn loops
search_code(pattern) Grep-style search across the project. Multi-turn loops
read_code(file, target) Read a whole file, a named function or class, or a line range (offset / limit, the same shape Claude Code uses). Multi-turn loops
glob(pattern) Find files by name pattern, for example ui/**/*.py. Multi-turn loops
edit_code(file, old_text, new_text) Replace an exact text span. The workhorse for small changes. Always
edit_function(file, function_name, replacement_body) Replace one function's body, located by parsing the file rather than matching text. Preserves indentation. Always
multi_edit(file, edits) Several exact replacements in one file in one call. Always
create_file(path, content) Add a new file to the project. Always
delete_file(path) Remove a file, so a refactor can retire what it replaced instead of leaving it to be imported by mistake. Always
syntax_check(file) Compile a file and report the first syntax error. Cheap, and the loop nudges the model to use it after edits. Always
run_code Run the project the way Test Run does and return the output and any traceback. Multi-turn loops
bash(command) Run a shell command in the project directory, under the whitelist / confirm / deny safety model described on the Agent Mode page. Agent Mode
web_search(query) Search the web. Agent Mode
web_fetch(url) Read a page as text. Agent Mode
load_skill(name) Pull the full text of a lazy skill listed in the skill index. Whenever lazy skills exist
question(prompt, options) Ask you a structured question mid-generation instead of guessing. Three per generation; not offered in Agent Mode or during auto-fix. Default mode

Two kinds of loop

Whittl runs tool calls in one of two loops, and the difference explains why some tools only appear sometimes.

Single-turn. The model gets the relevant code injected up front and only the action tools: edit, create, delete, syntax check. No exploration tools, because everything it needs is already in the message, and offering read_code would only invite a round of re-reading. This is the default for every backend except Claude when Agent Mode is off. It usually finishes in one or two API calls.

Multi-turn. The model gets the full tool set and works agentically: read, search, edit, check, run, repeat. Claude always uses this loop. Other backends use it when Agent Mode is on and the model is tier-S or tier-A, and the auto-fix path uses it for any model when the project is too large to inject whole (see below). Round caps come from the tier: 10 by default, 20 for tier-A and 50 for tier-S in Agent Mode.

Large projects: index-only context

Injecting a whole project into every round is fine at ten files and ruinous at sixty. Above a size that scales with the model's context window, Whittl switches to an index: the model receives the file list with line counts and reads only what it needs with read_code and search_code. You will see this in the log:

[TOOL-USE] Large project (535549 chars) — index-only context; AI reads files on demand

The same switch applies to auto-fix. On one field project this took a fix round from 364,000 input tokens to about 15,000, and made a model with a 200K window able to attempt the fix at all.

Reading the chat lines

Every call is humanised in chat. A few you will see often:

→ Reading canvas.py
→ Editing CanvasWidget.auto_detect_all_objects() in canvas.py
→ Checking syntax
→ Searching the web: "flet 0.28 page.window deprecated"
→ Editing align_panel.py (failed: old_text not found ...)

A failed edit is not an error in Whittl. It means the model's old_text did not match the file exactly, usually because the file changed since it last read it. The loop tells it so, with the closest matching lines, and it re-reads and retries.

What the tools cannot do

  • Leave the project. Every path is validated against the project directory. ../ and absolute paths are rejected.
  • Touch data/. Runtime and user data under data/ is never written by the tool loop.
  • Run arbitrary shell commands silently. Anything outside the bash whitelist asks you first; the deny list is blocked outright.

What's next