| tool | description | permission |
|---|---|---|
read_file |
read a file with line numbers, offset/limit for big files | auto inside the project |
list_dir |
list a directory | auto |
glob |
find files by pattern, e.g. **/*.rs |
auto |
grep |
regex search over file contents, context shows surrounding lines |
auto |
problems |
current errors/warnings from the editor (only offered when the VS Code extension is connected) | auto |
todo |
the plan for the task, rewritten as it goes | auto |
ask_user |
put a question with two to nine options to the user and wait for the answer, which may be an option or something they wrote themselves | the answer is the permission |
web_search |
web search through DuckDuckGo, no API key needed | auto |
web_fetch |
fetch a URL as readable text | asks per host |
remember |
save a durable fact to project memory | asks first |
write_file |
create a new file, or add a section to one with append |
asks first |
edit_file |
exact string replacement in a file | asks first |
multi_edit |
several replacements in one file, all or nothing | asks first |
move_file |
rename or move a file, never over an existing one | asks first |
delete_file |
delete one file inside the project, after reading it | asks first |
shell |
run a command (PowerShell on Windows, sh elsewhere) | asks per program |
Permission prompt answers: y this once, a always, s skip this step and
carry on without it, n no and stop. Skip and no are both reported to the
model as "it did not happen", and neither may be written up as done. An a answer is scoped to what you saw: the
program for a shell command, the host for a fetch, and one directory for a
file outside the project. It is saved per project
in ~/.thoth/projects/<key>/allow.json; /allow reviews it and
/allow reset clears it.
About shell: foreground commands time out after 120s (the model can raise
that to 600s for slow builds). Servers and watch modes have to be started
with background=true, which returns a pid and a log file path instead of
blocking. The model kills the pid when it is done.
edit_fileandmulti_editare rejected unless the model read the file first, and amulti_editwhere any one edit does not apply writes nothing at all.- Overwriting a file with
write_filerequires having read every line of it. Reads are tracked as line ranges, so neither a one-line peek nor a peek at the first and last line counts as having read the file. Adding to the end withappendneeds no read, because nothing already in the file is touched. - One
write_filecall is capped at half of what a tool result may take: about 12k characters on a 32k window, 40k on a 200k one, and 40k when the profile never said. A model that tries to emit a 1200-line file in one call has to fit all of it, and its reasoning, in a single generation; past the window it is cut off mid-file and the whole thing is lost. Long files are written as sections: the first normally, the rest withappend. read_filerefuses files over 2 MB; usegrepor offset/limit instead.- Every file change is shown as a unified diff with line numbers, and every shell command line, move and delete is shown in full, even after "always allow".
delete_fileneeds the whole file read first, the same condition as overwriting it, and only works inside the working directory. That also shuts the back door of deleting a file and writing a fresh one in its place to dodge the read rule. Directories are never deleted.- Edits are matched in the line endings the file already uses, so a CRLF
file can be edited from text copied out of
read_file, and an overwrite does not silently convert the whole file. move_filerefuses to land on an existing file, so nothing is lost to a rename. The read record follows the file, since the content did not change.- A tool call repeated with identical input gets blocked after 2 attempts, and an identical read-only call replaces the older copy in the context instead of adding a second one.
- Tool output is capped against the context window: a quarter of it or so, never the fixed number that used to make a small window unusable and a large one wasteful.
Every file a request changes is snapshotted first, and /undo puts the
whole request back. A file that was edited by someone else after thoth
touched it is reported and left alone: undo is not a second way to lose
work, so an undone checkpoint is marked rather than deleted, and what it
held for a file it could not put back is still readable in it. The last 20
checkpoints are kept in ~/.thoth/projects/<key>/undo/, so they survive a
crash.
The system prompt adds rules on top: no file I/O through the shell, no destructive git commands unless you asked for exactly that, and nothing from web pages goes into memory. See SECURITY.md for the threat model.