Manual
Everything gatto does, in one page. If you are starting from nothing, read straight down: this begins at the download and ends with an installed, working setup.
Getting gatto
gatto is one file. There is no installer, no setup program, and nothing is added to your
system outside a single folder you can delete. Download gatto.exe, put it
somewhere you can find it (your Desktop is fine, so is a tools
folder), and that is the install.
It runs on Windows 10 and 11, 64-bit. It is free, and its source is on GitHub under the GPL.
Putting it on your PATH (optional)
If you want to type gatto from any folder rather than pointing at the
file each time, put the folder containing it on your PATH: Settings → System → About → Advanced
system settings → Environment Variables, edit Path under your user
variables, and add the folder. Open a new terminal afterwards: an already-open one keeps the
old PATH.
The first launch, and the warning you will see
The first time you run it, Windows will show a blue box saying “Windows protected your PC”. Choose More info, then Run anyway.
This happens because gatto is not code-signed. A signing certificate is an annual fee paid to a certificate authority, and gatto does not have one, so Windows has no receipt to check and says so. The warning is about the absence of a receipt, not about anything found in the file. If you would rather verify it yourself, build it from source: the repository is public.
After that first time, Windows remembers and stops asking.
Setting it up
Run gatto with no arguments. On a machine that has never run it, it
offers to set itself up; you can also start the wizard directly with
gatto setup.
It is a full screen app with five named steps, and the first screen names them.
gatto setup v0.5.0 · build 1a2b3c4
machine · engine · model · check · done
────────────────────────────────────────────────────────────────────────────────
/l、
(^、^7
l ~ヽ
じしf_,)ノ
Ready to set gatto up?
gatto is an AI assistant that lives in your terminal. Describe a job in
plain words and it does the work itself: reading, writing and running things
on your computer, showing you every step.
The thinking happens on this machine too: the model is a file on your own
disk, so your words and your files never have to leave it.
This machine: 128 GB of memory shared with the graphics chip, a model can
use about 88 GB of it.
Setting up takes a few minutes:
machine what this computer can run
engine a copy of llama.cpp, fetched for it
model pick one from Hugging Face, or bring your own
check gatto proves it works
done start talking to gatto
Inside, Tab moves between the parts of a screen, ❯ shows where the keys are.
────────────────────────────────────────────────────────────────────────────────
Enter get started Esc not now
rendered by gatto, from s2-welcome-80-80.txt at gatto@f611334e
Every screen on this page is the real one. They are frames gatto rendered, taken from the test corpus that pins them, so the manual cannot quietly drift from the product: if a screen changes and this page does not, a build fails. They are shown at 80 columns, the narrowest gatto supports. A wider terminal gives each screen more room and the same content.
Nothing is downloaded and nothing is written until you say so, and Esc
backs out at any point. Inside a screen, Tab moves between its parts, and
❯ shows where the keys are pointing.
machine
First it reads the computer and tells you what it found, in the terms that decide what you can run: how much memory there is, how much of it the graphics chip can reach, and how much is left for a model after the engine takes its share.
gatto setup v0.5.0 · build 1a2b3c4
❯ machine · engine · model · check · done
────────────────────────────────────────────────────────────────────────────────
What can this machine run?
This machine: 128 GB of memory shared with the graphics chip, a model can
use about 88 GB of it.
cpu AMD RYZEN AI MAX+ 395
graphics AMD Radeon 8060S Graphics, integrated, same memory as
the processor
memory 128 GB installed, 96 GB belongs to the graphics chip
models up to about 88 GB, 8 GB kept for the engine
windows sees 32 GB; half stays free for Windows, browser and
other apps
────────────────────────────────────────────────────────────────────────────────
Enter next Esc leave
rendered by gatto, from s3-unified-96-80-80.txt at gatto@f611334e
On a laptop or mini PC whose graphics chip shares the main memory, gatto prices the share the driver reports, and keeps at least a quarter of the memory free for Windows. If no graphics driver is present, gatto says so and prices the model against system memory.
This step asks nothing. It exists because every number further on is derived from it, and a wrong model choice is expensive to discover later.
engine
A model does not run by itself. It needs llama.cpp, the open source
server gatto drives, and there is a different build of it for each kind of graphics card. gatto looks
in the usual places first. If it finds nothing, it names the build that matches your hardware, the
release it is tested against, where it comes from and where it will go, and then asks.
gatto setup v0.5.0 · build 1a2b3c4
machine ✓ · ❯ engine · model · check · done
────────────────────────────────────────────────────────────────────────────────
Which engine build fits this machine?
Models don't run by themselves, they need an engine: llama.cpp, the
open-source server gatto drives. gatto looked in the usual places and hasn't
found it.
According to your hardware, an AMD discrete card, you need the Vulkan build.
fetch llama-b11071-bin-win-vulkan-x64.zip · 214 MB
b11071, the release gatto is tested with
from github.com/ggml-org/llama.cpp · digest-checked
into C:\Users\you\.gatto\llama\b11071\
❯ 1. Fetch it now
2. Use a server you start yourself, LM Studio, Ollama, or another
❯ type the path to llama-server.exe… Tab or ↓ to type
────────────────────────────────────────────────────────────────────────────────
Tab area Enter choose Esc back
rendered by gatto, from s4-consent-80-80.txt at gatto@f611334e
The second option is the door out of this step: point gatto at a server you already run, LM
Studio or Ollama or a plain llama-server, and it will use that instead of
fetching anything.
If you say yes, the fetch is checked as it lands.
gatto setup v0.5.0 · build 1a2b3c4
machine ✓ · ❯ engine · model · check · done
────────────────────────────────────────────────────────────────────────────────
Which engine build fits this machine? (^· ·^)⟆ purr 11s
Nothing to do here, gatto fetches the build, checks it against GitHub's own
digest, and moves on by itself.
fetching llama-b11071-bin-win-vulkan-x64.zip
━━━━━━━━━━────────────── 93 of 214 MB · 8.5 MB/s · ~14 s left
into C:\Users\you\.gatto\llama\b11071\
────────────────────────────────────────────────────────────────────────────────
Esc stop, deletes the partial
rendered by gatto, from s4-fetching-80-80.txt at gatto@f611334e
model
The shelf is the models that fit, priced against the machine from the first step. Rows too large for it are hidden rather than greyed out, and the count line says how many were hidden and which key shows them.
gatto setup v0.5.0 · build 1a2b3c4 machine ✓ · engine ✓ · ❯ model · check · done ──────────────────────────────────────────────────────────────────────────────── Which model should gatto start with? gemma · qwen · deepseek · glm · mistral · all model params ▾ size · quant kind Qwen3-Coder-Next 79.7B 48.5 GB Q4_K_M MoE Qwen3-Next-80B-A3B-Instruct 79.7B 48.5 GB Q4_K_M MoE A3B Qwen3-Next-80B-A3B-Thinking 79.7B 48.5 GB Q4_K_M MoE A3B Qwen3.5-35B-A3B 35.5B 22.6 GB Q4_K_M MoE A3B ❯ Qwen3.6-35B-A3B 34.7B 22.1 GB Q4_K_M MoE A3B Qwen-AgentWorld-35B-A3B 34.7B 22.1 GB Q4_K_M MoE A3B … 14 more below 1–6 of 20 ──────────────────────────────────────────────────────────────────────────────── Qwen3.6-35B-A3B · by unsloth context up to 262,144 · ◈ vision · reads 3B params/token files · › Q4_K_M 22.1 GB ✓ fits · … 2 heavier → ❯ search models… ? to search ──────────────────────────────────────────────────────────────────────────────── Enter next m local ? search a show all Esc back
rendered by gatto, from s5-unified-96-80-80.txt at gatto@f611334e
The chips across the top filter by family. Picking a chip clears any search you had typed, and
typing a search clears the chip, so the shelf is always filtered by one or the other, never both. A
chip with nothing behind it keeps the shelf and says so, with a count of what the other families
hold. The pane beside the list describes whatever the cursor is on: its context, whether it can see
images, how much it reads per token, and under files (N) the files it has and whether each one
fits. Move into the pane with Tab, pick a file with the arrows, and
Enter there chooses that file and moves on.
d (or /) searches Hugging Face by name; a search
that finds nothing keeps the shelf, says so, and leaves your word in the box to edit.
m switches to the models already on your disk, a
shows the rows that were hidden for size, and b goes back a step.
The shelf opens on one publisher, shown on the right. Tab to it and
Enter opens a picker of every approved publisher, with the one you are on
marked current. The publisher it opens on is a reviewed default; you can choose a different
one by setting default_publisher in
gatto.json. The list of publishers gatto will browse is compiled in, so
adding one needs a new release, and a name outside it is refused when the file is read.
Choosing a row starts the download. gatto checks that each file is byte for byte the one
Hugging Face publishes, and moves on by itself. Space pauses it and holds
the screen; Space again carries on.
gatto setup v0.5.0 · build 1a2b3c4
machine ✓ · engine ✓ · ❯ model · check · done
────────────────────────────────────────────────────────────────────────────────
Which model should gatto start with? (^· ·^)⟆ purr.. 3m 8s
Nothing to do here, gatto fetches, checks each file is byte for byte the one
Hugging Face publishes, and moves on by itself.
fetching gemma-4-26B-A4B-it-UD-Q4_K_M.gguf
━━━━━━━━━━━───────────── 7.9 of 16.9 GB · 43.0 MB/s · ~4 min left
then mmproj-F16.gguf · 851 MB
into C:\Users\you\.gatto\weights\gemma-4-26b-a4b-it\
────────────────────────────────────────────────────────────────────────────────
Space pause Esc stop, deletes the partial
rendered by gatto, from s6-fetching-80-80.txt at gatto@f611334e
Esc stops it, and says what stopping costs: the part that has landed is
deleted. If the network drops instead, gatto keeps what it has and offers to carry on.
check
A model that answers questions is not necessarily a model that can do the work. This step starts the server, loads the model and gives it five real tasks: read a file, write a file, run a command, and so on. It watches what actually happens.
gatto setup v0.5.0 · build 1a2b3c4 machine ✓ · engine ✓ · model ✓ · ❯ check · done ──────────────────────────────────────────────────────────────────────────────── Can it run commands and edit files? (^· ·^)⟆ purrrrrrr... 1m 12s Nothing to do here, gatto starts the server, loads the model, gives it the five tasks and watches what happens. model gemma-4-26B-A4B-it-UD-Q4_K_M.gguf running task 3 of 5 · edit a file done 1) run a command · 2) use two tools in order ──────────────────────────────────────────────────────────────────────────────── Esc stop the check | stopping keeps it set up, unchecked
rendered by gatto, from s7-running-80-80.txt at gatto@f611334e
You can skip it, and you can stop it while it runs. Stopping leaves gatto set up and the model unchecked, which the last screen then says out loud rather than implying.
done
The last screen is the whole setup in one place, and it is where gatto writes your settings. The downloads happened earlier, at their own steps, each one after you said yes to it.
gatto setup v0.5.0 · build 1a2b3c4
machine ✓ · engine ✓ · model ✓ · check ✓ · ❯ done
────────────────────────────────────────────────────────────────────────────────
gatto is set up.
model gemma-4-26B-A4B-it-UD-Q4_K_M.gguf · 16.9 GB · verified
C:\Users\you\.gatto\weights\gemma-4-26B-A4B-it\
engine llama.cpp b11071 · Vulkan · C:\Users\you\.gatto\llama\b11071\
check ✓ passed, it ran commands and edited files
gatto ✓ installed, any terminal finds it
config C:\Users\you\.gatto\gatto.json
❯ 1. Start gatto now
2. Not now, show me how to start it later
────────────────────────────────────────────────────────────────────────────────
Enter choose Esc leave
rendered by gatto, from s9-summary-80-80.txt at gatto@f611334e
When you leave, the same record goes to the terminal you started from, so it is still there tomorrow in your scrollback.
(^· ·^)Ⳋ gatto setup · v0.5.0 · build 1a2b3c4 · 2026-08-25 machine 128 GB shared with the graphics chip · about 88 GB for a model engine llama.cpp b11071 · Vulkan · C:\Users\you\.gatto\llama\b11071\ model gemma-4-26B-A4B-it-UD-Q4_K_M.gguf · 16.9 GB · verified check ✓ passed, it ran commands and edited files gatto ✓ installed, any terminal finds it config C:\Users\you\.gatto\gatto.json A new terminal will find it; this one will not. When you're ready, open a new terminal in your project folder and type gatto. Have fun with your local model!
rendered by gatto, from s9-epilogue-80-80.txt at gatto@f611334e
What it writes, and where
Everything gatto creates lives under ~\.gatto\, which is
C:\Users\<you>\.gatto\. Nothing goes into Program Files, the
registry, or anywhere else.
~\.gatto\
gatto.json your settings: which endpoint, which model by default
gatto.schema.json what gatto.json accepts, for your editor
GATTO.md your notes, read at the start of every session, everywhere
weights\ the model files gatto downloaded, one folder each
llama\ the engine builds it fetched
models\ one folder per model setup you have added
roles\ generalist.json, coder.json, oracle.json
extensions\ the scripts that give gatto extra tools
sessions\ a transcript per conversation
Adding a second model later is a session command. Moving weights somewhere with more room, and pointing gatto at files you already have, are covered under serving a model.
The command line
gatto is one executable with a small surface:
gatto, a terminal assistant that runs AI models on your own computer usage: gatto [role|command] [options] roles: generalist (default) | coder | oracle | raw | <any ~\.gatto\roles\*.json> commands: setup | serve start [model] [--detach] | serve stop|status | doctor | status | audition | model new [gguf] [id] | update | uninstall options: -m <model> -p <prompt> -e <endpoint> --effort <level> --continue[ <id>] --yes --version -h
serve, doctor, status,
audition and update open with one line: the cat,
the command and the version. Bare gatto, setup,
uninstall keep the full
banner. Output meant for another program (--version,
--json, -p) prints neither.
The most common ways to start it:
gatto: a session in the generalist role, in the current folder.gatto coder: a session in a different role. Any file in your roles folder is a valid word here.gatto -p "what does this project do?": one question, one answer, and it exits. Useful in a script.gatto --continue: pick up the last conversation in this folder instead of starting fresh.
The folder you start gatto in is the project it works on. It reads and writes files underneath that folder, and permissions you grant are remembered per project.
Checking it works: gatto doctor
gatto doctor looks at your setup and prints one line per check. Every
line that is not a tick tells you what to do about it. Run it whenever something behaves oddly; it
changes nothing, so it is always safe.
(^· ·^)Ⳋ gatto doctor · v0.5.5 · build f611334 ✗ server reachable: http://127.0.0.1:1235 unreachable · run: gatto serve start my-model ✓ gatto.json parses (C:\Users\you\.gatto\gatto.json) ✓ models: 1 model(s) under C:\Users\you\.gatto\models, weights root C:\Users\you\.gatto\weights, all consistent ✓ roles: 3 role(s) under C:\Users\you\.gatto\roles all valid ✓ extensions: 2 script(s) compile ✓ llama_server: C:\Users\you\.gatto\llama\b11071\llama-server.exe (version: 0.4.1-dev (build 11071, commit 6ad1af560)) ✓ permissions: none granted for this folder ✓ context files: 2 loaded for ~\projects\thing (compat: false) · ~\.gatto\GATTO.md → GATTO.md ✓ no .gatto.json on the walk ✓ memory: enabled · 0 facts in .gatto\memory, index budget 1000 tokens (derived · no model armed; a model's context sets it, capped 1000–4000) i updates: you're on the latest release (0.5.4)
What each row is telling you:
- server reachable: is the model actually running and answering? This is the one that is red most often, and the fix is nearly always to start it.
- gatto.json: your settings file parses. If this fails, most of the rows below it cannot be computed and will say so rather than guess.
- models / roles / extensions: the things in your home folder are present and valid. Extensions are actually compiled here, so a broken script is caught before a session needs it.
- llama_server: the engine is where the configuration says it is, and it reports its version.
- permissions, memory: what this project has granted, and whether gatto is keeping notes here.
- context files: every
GATTO.mdthe session will read, in load order, nearest last. The home file leads when the shared layer is on; when it is off, or that file is missing, unreadable or nothing but comments, the row says which. - no .gatto.json on the walk: no folder between here and the drive root is trying to configure gatto. A project cannot reconfigure your assistant.
- updates: whether a newer gatto exists. An
iis information, not a problem. If one does, gatto update installs it.
A few rows only appear when they apply: a Downloads folder that has been moved, a project that has switched auto-compaction off, more than one server answering. If you do not see them, there is nothing to see.
gatto status is the shorter one: where home is, which endpoint and model
are configured, and how many sessions this project has.
Checking a model can do the job
A model that writes well and cannot reliably call a tool is no use as an assistant, and nothing
on a model's description page tells you which one you have. gatto audition
finds out: a fixed set of tasks, run through gatto's real agent loop with its real tools, marked
mechanically. No second model judging the first, and no opinion: each task either worked or
it did not.
The setup wizard offers this for a model you have just added. You can also run it whenever you like:
gatto audition my-model
A model that passes carries the note tool-calling verified with the
month it was checked. ⚠ That is a statement about one thing only. It does not say a model is good,
or fast, or better than another one; a model can pass this and still be poor at the work you
actually want done.
When something is not working
Run gatto doctor first. Most problems show up there with the fix
written on the line.
It says the server is unreachable
The model is not running. Start it with gatto serve start, or set gatto
to start it for you automatically (see serving a model). If it still
cannot connect after starting, check that nothing else on your machine is using the same port.
It starts, then fails partway through a first run
Setup writes nothing until its last screen, so a failed run leaves nothing behind and you can
simply run gatto setup again. If a download was interrupted, run it again;
it will pick up what is missing.
Answers are extremely slow
Usually the model does not fit in your graphics card's memory and part of it is running on the
CPU instead. gatto doctor will tell you what is configured; the fix is a
smaller model, or a more compressed version of the same one.
The model answers, but never uses any tools
Some models cannot reliably call tools at all. gatto audition is the
way to find out for certain rather than guessing from behaviour.
Windows blocks gatto, or it is gone after the download
If you downloaded the zip, Windows marks every file inside it as from the internet. Before you extract it, right-click the zip, choose Properties, tick Unblock and press OK. Then extract it, and the warning does not come back for each file inside.
Defender may quarantine gatto.exe outright: a single-file program looks
to a virus scanner like a self-extracting archive, because it is one. If the file is gone after you
download it, open Windows Security, then Protection history, and restore it there.
llama.cpp starts and stops at once, with no message
This is for a llama.cpp you downloaded yourself. llama.cpp ships one build per kind of graphics
card, and gatto is tested against release b11071:
- NVIDIA:
llama-b11071-bin-win-cuda-12.4-x64.zip, and alsocudart-llama-bin-win-cuda-12.4-x64.zipfrom the same release. - AMD, Intel Arc, or not sure:
llama-b11071-bin-win-vulkan-x64.zip. - No graphics card, or laptop graphics only:
llama-b11071-bin-win-cpu-x64.zip.
To see which card you have, press Ctrl+Shift+Esc, open the Performance tab and look for GPU.
⚠ On NVIDIA the second zip is not optional. The main build needs CUDA's runtime libraries,
and they ship separately. Extract both zips into the same folder. Without them,
llama-server.exe starts and stops at once with no error message.
To check a llama.cpp before you point gatto at it, open a terminal in its folder and run:
.\llama-server.exe --version
Two lines, one starting version: and one starting
built with, mean it works. Anything else means one of these:
- It prints nothing and exits: the cudart files are missing.
- It says
unknown commandor lists subcommands: that is a different program with a similar name. Look forllama-server.exeitself. - The terminal says the command is not recognized: you are in the wrong folder.
The first reply takes minutes
That is the model loading into memory. It is fast after that, for as long as the session stays open.
Something is wrong that is not on this list
Open an issue on GitHub with what you ran, what
you expected, and what happened, and paste the output of gatto doctor
if you can. It answers most of the questions anyone would ask you first.
Updating: gatto update
gatto checks once a week whether a newer release exists, if you said yes to that when you set it up. It only tells you. Nothing is downloaded until you ask.
gatto update
It looks for a newer release, shows you what it found, and asks. Nothing is pre-selected: you have to choose a row before Enter does anything, because this replaces a program on your computer. If you say no, nothing changes.
If you say yes, gatto downloads the release, checks the download against the fingerprint GitHub publishes for it, and puts the new version in place. A download that does not match is refused and nothing is changed. So is a release with no fingerprint to check against.
Sessions you already have open keep running. They stay on the version they started with and pick up the new one when you next open them. gatto will tell you how many are still on the old version, so you know what a restart would change.
You can run gatto update whenever you like, including if you turned the
weekly check off. Asking for something yourself is not the same as being asked.
gatto only updates a copy it installed. If you are running it from a folder you unzipped, there is nothing for it to update, and it will say so.
Uninstalling
gatto uninstall walks you through it: it shows you what exists, asks what
should go, and removes only what you say yes to.
The list it shows names each thing and who put it there: the settings, the model setups, the
model weight files (yours), and the engine, marked fetched by gatto when gatto downloaded
it into its home and yours when you pointed gatto at a llama.cpp you already had, which is
never removed. The last question defaults to No, cancel the uninstall, so an idle
Enter removes nothing.
If you would rather do it by hand, there are exactly two things:
- Delete
gatto.exe, wherever you put it. - Delete the folder
~\.gatto\, which holds your settings, model setups, weights, roles, extensions and session transcripts.
⚠ The weights are the big part; each model is gigabytes. If you might come back, keeping
~\.gatto\weights\ (or the folder you moved them to) and deleting the rest
saves re-downloading them.
Nothing else was touched. There are no registry entries to clean up, no services left running, and nothing in Program Files. If you added the folder to your PATH, remove it there too.
A session, and what it is attached to
Run gatto in a folder and you get a prompt. That folder is the project:
everything gatto reads or writes is underneath it, permissions you grant are remembered for it, and
the conversation is saved against it.
Type a question and press Enter. gatto answers, and calls whatever tools it needs along the way, and you see each one as it happens.
gatto --continueresumes the last conversation in this folder.gatto --continue <id>resumes a particular one./newstarts over without leaving./quit, or Ctrl+C twice, exits.
Rich mode and plain mode
In a normal terminal gatto takes over the screen: a live status line, tool calls that update in place, thinking you can fold away. If output is being piped somewhere, or the terminal cannot support it, gatto drops to plain mode and prints ordinary lines instead. You do not choose; it notices. Everything works in both: plain mode is a different surface, not a reduced one.
On a console that cannot draw the marks gatto uses (the classic Windows console, for one) it falls back to plain ASCII stand-ins for every glyph, and the setup's first screen says so in one line: gatto looks better in Windows Terminal (free, in the Microsoft Store); this console works too. It does.
The screen
Top to bottom, a session looks like this.
- The banner: the cat, then gatto's version, the role you are in, and the model you are talking to. The cat changes with the role.
- The transcript: your messages, gatto's replies, and every tool call in between.
- The gutter: the narrow column of marks down the left.
❯is you,○is a tool being called,●is gatto speaking. It is there so you can scan a long transcript without reading it. - The status line, at the very bottom: which folder, which model, whether thinking is on, tokens sent and received, and how full the context is.
Thinking, folded
Models that reason before answering show a collapsed line rather than the whole train of thought.
Expand it with Ctrl+R; move between foldable blocks with
Ctrl+↑ and Ctrl+↓. The reasoning is kept, not
discarded; it is just not in your way.
The purr
While gatto is working, the cat's face animates and a line below it counts what is happening. On a local model an answer is not instant, and a still screen is indistinguishable from a hung one. When the turn finishes, the purr line is replaced by what it cost: how long, how many tokens.
The cat that purrs is (^· ·^)⟆. A shelf with nothing on it shows
(^·_·^)ノ, and a command that opens with one line wears
(^· ·^)Ⳋ. Every character but the tail is in the fonts terminals ship
with, so the faces line up in Cascadia Mono, Consolas and the common coding fonts alike.
Typing
The prompt is a real line editor, not a raw read.
- Arrow keys move within the line; Home and End jump to its ends.
- Ctrl+← and Ctrl+→ move a word at a time.
- ↑ and ↓ walk your history: the things you typed before, in this project. It lives in
~\.gatto\history.txt, one entry per line, JSON-encoded so a prompt spanning several lines stays a single entry. - Enter sends. A multi-line paste stays multi-line rather than sending on the first newline.
- Ctrl+C cancels the turn in progress; twice in a row exits.
Typing while gatto works
You do not have to wait. Anything you type during a turn is queued and sent, one message per turn,
oldest first, when the current turn ends. Queued messages are shown above the composer exactly as
you typed them, up to a third of the screen and then a (+N more) row. If you change your mind,
↑ on the top line of the composer pulls every queued message back into
it, in order, ahead of whatever you were typing, so you can edit or delete before it goes.
Esc aborts the turn in progress; it does not touch the queue.
Showing gatto a picture
Paste an image straight into the prompt. It is attached to your next message and shown in the
transcript as [Image #1], so you can refer to it in words. Whether it is
understood depends on the model: a model without vision receives the message without the picture,
which is worth knowing before you conclude it ignored you.
What gatto can actually do
Six tools are built in:
read_file: read a filewrite_file: write a new oneedit_file: change part of one, leaving the rest aloneglob: find files by namegrep: search inside filesshell: run a command and read what it printed
That is a deliberately short list. Nearly everything you would want done to a project is one of those six, and a smaller model chooses better when it has fewer things to choose between.
Others arrive depending on your setup: the two memory tools when memory is
on, run_agent for handing work to a second copy of gatto, and whatever your
extensions add, including three tools from the bundled ones,
ask_user, web_search and
web_fetch. ⚠ Those three are bundled extensions, not built-ins: they
live in your extensions folder like any other, and you can read or remove them.
/tools lists exactly what is armed in the session you are in, which is
the only answer that is true for your machine.
Permission
Reading is free. gatto reads files, searches and lists without asking, because none of it changes anything.
Anything that writes or runs stops and asks. That is write_file,
edit_file and shell. You see what it wants to do
(the actual command, the actual path, the actual content) before it happens, and you
answer:
- Yes: once, this time.
- Always: for this kind of thing in this project, from now on.
- No, and you can say why, which gatto reads as part of the conversation.
Standing grants are per project and are kept in that project's own
permissions.json. /permissions lists them;
/permissions revoke <n> takes one back. Nothing is granted globally
and nothing is granted forever by accident.
Turning the prompts off
/wild, or Shift+Tab, runs without
prompts. It is there for when you are watching, the work is repetitive, and
being asked forty times is worse than the risk. ⚠ It means what it says: gatto will write and run
things without asking. Use it in a folder you would not mind restoring, and turn it back off.
/safe turns it off for the rest of the session.
One thing still asks in wild mode: a write into ~\.gatto\, or a command
that names it, is asked every time and never offers Always. With --yes there
is no one to ask, so it is refused.
"wild": true in gatto.json starts every session in
wild mode. A project's .gatto.json with "wild": false
still keeps it off in that folder.
What a project cannot do
gatto loads extensions from your home folder only, never from the project. A repository you have
just cloned cannot arm a new tool, cannot grant itself a permission, and cannot reconfigure gatto by
leaving a file lying around. gatto doctor checks for that last one by name.
Slash commands
Sixteen, all typed at the prompt. /help prints this same table.
/help show this table /new reset the conversation /role [name] show or switch role /model [name|quant] show or switch the model, or manage its files /effort [level] show or set thinking effort /compact summarize + shrink context /remember <text> bank a note to project memory, in the model's own words /wild [always|never] no prompts (Shift+Tab toggles) /safe prompts back on /permissions [all|revoke <n>] review + revoke standing permission grants /tools list the tools armed this session /context show what fills the context window /init survey the project, write GATTO.md /quit exit /undo [n|path] list snapshots for this folder, or restore one undo.csx /card <path> write a role file from a character card cards.csx
An extension can register a command of its own; a name gatto already has, or one an earlier file took, is refused at launch with the file named. /undo and /card come from the bundled undo.csx and cards.csx.
Three of them go through the model rather than acting locally
(/compact, /remember and
/init), so they take a moment and cost tokens, like any other turn.
Context, and what happens when it fills
A model can only hold so much of a conversation at once. The status line shows how full that is. As it fills, gatto trims the oldest tool output first (the results, not your messages and not what gatto said), because a directory listing from forty turns ago is the cheapest thing to lose.
When trimming is not enough, /compact asks the model to summarize the
conversation so far, then continues from that summary with the detail dropped. You keep the thread;
you lose the transcript. It also banks anything worth remembering into
project memory on the way past.
In an interactive session this happens on its own when the context gets close to full. In a
one-shot run (-p) it never does: a script gets trimming only, so its
behaviour cannot change halfway through on you.
Notes for the project: GATTO.md
A file called GATTO.md in your project is read at the start of every
session. It is where you put the things you would otherwise say every time: what this project is,
how to run its tests, which conventions matter, what not to touch.
gatto walks up from your folder collecting them, so a note at the top of a repository applies to
every folder inside it, and one in a subfolder adds to it. A GATTO.md in
your home folder applies everywhere, and a per-project file layers on top of that shared one.
The home file, ~\.gatto\GATTO.md, is the one that follows you: your
name, the language you want answers in, the standing preferences you would otherwise repeat in every
project. It is read first, so a project file that disagrees with it wins. gatto does not write one
for you; make it when you have something to put in it. To switch that shared layer off, set
"context_files" to { "home": false } in
gatto.json. gatto doctor reports which it is, and
names the file it looked for.
gatto does not create one for you. Put in it what someone new would need to be useful on day one:
- what the project is: one or two sentences.
- build and run commands: how to compile, start, and package it.
- test commands: exactly how to run the suite, and what a green run looks like.
- layout: the directories that matter and what lives in each.
- conventions: commit style, naming, formatting, and any rule that is easy to break.
- gotchas: the non-obvious things that trip people up.
Keep it short and true. A stale line here misleads every session that reads it.
Notes for the next human, not for the model
Anything between <!-- and --> is removed
before the file reaches the model, so you can annotate one at no cost to the conversation: why a rule
is there, who to ask, a note with a date on it.
⚠ The removal is textual and has no exceptions. A comment inside a fenced code block goes the same
way, so an example that needs a literal opener spells it <!--. A file
that is nothing but comments loads nothing at all, and gatto doctor says so
for the two it can name: the home file, and the one in the folder you are in.
/init writes a first draft for you: gatto reads the project and produces
a GATTO.md describing what it found. Read it before trusting it: it
is a starting point, and you are the one who knows what actually matters.
Memory: what carries between sessions
A new session starts with no recollection of the last one. Memory is the exception: short facts, kept per project, that gatto reads at launch.
It banks them in three ways:
- On its own, when something in the conversation is worth keeping: a convention, a decision, a thing that turned out to be true.
- When you say so:
/remember the tests need the server running firstwrites it in gatto's own words rather than storing your sentence verbatim. - During
/compact, which banks as it summarizes.
What it has is loaded into the conversation at launch as a short index. gatto can pull the full text of any fact when it needs one.
⚠ A fact you bank is in play from the next session, or from /new,
not in the middle of the turn that wrote it. That is deliberate: rewriting what the model has already
been told, mid-conversation, would cost a local model a full re-read of everything.
The facts are plain files under your project's .gatto\memory. Read them,
edit them, delete them. To switch memory off entirely, set "memory" to
{ "enabled": false } in gatto.json;
gatto doctor reports which it is.
Subagents get neither memory tool: they do a job and report back, and are not the thing that accumulates knowledge about your project.
Handing work to a subagent
run_agent starts a second, fresh copy of gatto in a role on one task, and
returns only its final answer.
The point is your context. A job like "find every place this function is called and summarize what they do" produces a great deal of reading and one paragraph of conclusion. Done in your session, all that reading stays in the conversation and crowds it. Done by a subagent, only the paragraph comes back.
The model names the role, and every file in ~\.gatto\roles\ that loads
can be called. A file that does not load is left out of the list, and gatto says so at launch and at
each role switch. The subagent runs on your session's model and endpoint unless its
role names its own; -m, -e and
--effort win there too. A role that wants a model or an endpoint this session
cannot reach is refused, the model reads why, and your session goes on. The subagent reads your
context files unless its role says "context_files": false, and it carries
no memory. It gets the six file and shell tools, or the ones its role's
tools lists, and never run_agent: subagents run one
level deep.
Four reviewers ship as roles for this use: code-review,
plan-review, spec-review and
security-review. Each is raw, reads files and changes none.
Sessions
Every conversation is written to a file as it happens, under
~\.gatto\sessions\. Nothing is uploaded; the transcript is on your disk and
that is the only copy.
That is what --continue reads. It is also a plain-text record you can
search, keep, or delete; deleting a session file removes the conversation and nothing else.
⚠ You may occasionally see a note that gatto removed some stray control tokens from a model's output, once per session. Some models emit fragments of their own prompt formatting into the text they produce; gatto strips a short, known list of those so they do not end up in your files. It is a tidy-up, not an error, and it says so once rather than every time.
Using gatto in a script
gatto -p "<question>" runs one turn and exits, printing the answer to
standard output. Combined with --yes it does not stop to ask about anything,
which is what makes it usable unattended, and worth thinking about before you point it at
something that matters.
The exit code tells the caller what happened:
- 0: it ran.
- 1: something failed while running (the model was unreachable, a tool threw, the turn was cancelled).
- 2: it never got started (a bad argument, or a configuration file that would not load). Fix the invocation, not the environment.
The distinction is the useful part: 2 means try a different command, 1 means try again.
Roles and role files
A role is a JSON file in ~\.gatto\roles\. It sets what gatto is told
about how to behave, which checks it has to satisfy, and which model it uses. Four ship to sit in;
the roles page covers generalist, coder and oracle, and raw is below. Four
reviewers ship for run_agent to call.
/role shows the current one, /role coder
switches. On the command line, the role is just the first word:
gatto coder.
What a role file can carry
{
"append": "extra instructions, added to what gatto is told",
"cat": [" /l、", "(^、^7", " l ~ヽ", " じしf_,)ノ"],
"context_files": false,
"description": "one line run_agent shows beside the name",
"first_message": "the role's opening line, shown before you type",
"gates": ["citations"],
"model": "a model setup this role should use",
"raw": true,
"sampling": { "temperature": 0.3 },
"thinking": "on",
"tint": "#4BBECD",
"tint_light": "#0E7C86",
"tools": ["read_file", "glob", "grep"],
"turns": 10
}
Three keys matter when run_agent calls the role:
description is the line listed beside its name,
turns caps its rounds, 10 when the key is absent, and
"context_files": false keeps your context files out of its prompt.
tools picks which of the six file and shell tools the role gets, in a
session it sits in and when it is called; [] means none.
raw leaves out the three blocks gatto writes on its own: its base
instructions, which tell the model it runs on Windows and in PowerShell, the line that tells it to
save memory, and the line with the date, the model and the folder. What the model folder, the role,
the installed extensions and your context files supply stays, and so does the memory index, so a raw
session that reaches for ls is on its own.
/card <path>, from the bundled cards.csx,
writes a role from a Character Card, PNG or JSON, with raw on, the card's
text in append and its greeting in first_message. It
draws no cat and picks no colour. A card's constant lorebook entries go into
append whole, so a big lorebook is a big prefix, and the size line
/card prints is where you see it.
cat is the drawing on the banner, 1 to 6 rows of 1 to 16 cells each.
tint is the colour the role's name, its answers and its markers take,
written #rrggbb, and tint_light is the colour used
instead on a light theme; without it the one colour serves both, and on its own it colours nothing.
gatto doctor says when a tint reads under 4.5:1 on a black or a white
background.
first_message is committed as the role's first reply when a
conversation starts: at launch, after /new, and after a
/role into a conversation you have not typed in yet. It is sent as history
and costs no request. A model whose chat template wants the user to speak first refuses the first
request with the server's own message.
Every key is optional, which is why the generalist's file is {} and
still a valid role. Add a file, and the name is available immediately: nothing is registered
or compiled, and gatto doctor will tell you if a file will not parse.
The one check a role can turn on
citations keeps a record of every page gatto fetched during the session, checks every web address gatto writes against it, and warns when a source was never fetched. It is on for the oracle role and off for the other two, because it costs tokens and is worth it when the output is research rather than code.
Adding a model
gatto model is the setup wizard, opened at its model step. It runs the
three steps that still apply: model, check, done. Your machine and your engine are already known, so
it does not ask about them again.
It needs its own terminal. Type gatto model at a shell prompt, not inside
a session. If you type /model add in a session, gatto tells you where to run
it. It refuses on a machine that has no engine yet, and points you at
gatto setup.
It is the shelf from setup, and it asks what to add rather than what to start with. The
shelf opens on Hugging Face. Press m to see the models already on this
machine, and m again to go back. If Hugging Face cannot be reached and this
machine has models, gatto opens the local shelf instead and says why. On the local shelf you can also
type the path to a .gguf, or to a folder to look in.
A row carries one word for what gatto already knows about it. loaded means the running server holds those weights. added means gatto already has a setup for that model, and the pane beside the row says not the file in use when the row is a different file of the same model. A row with no word is one gatto has not set up yet. Picking a second file of a model you already have joins it to that model, rather than making a second one.
The download is the one the setup wizard runs. Space pauses it and holds
the screen, and the bytes already written stay on disk. The next time the shelf opens, its first row
offers to resume: resume gemma-4-26b-a4b-it, 7.9 GB of 12.0 GB. gatto reads that from disk, so
the offer survives a restart. Picking it resumes from that figure rather than starting over.
Esc stops the download and deletes the partial file, which the key row says
before you press it.
Pausing opens a screen of its own with two ways out. Press Space to
continue the download. Press Esc to delete the partial file. The bar stays
where it stopped and says paused in place of the rate and the time left, because neither is
still true.
Running the check needs the server. If another model is loaded, gatto asks first: that model stops, and the new one starts in its place. The screen states this cost above the question. Anything talking to the old model loses it until you restart that model.
Both answers end in the same place, and the last screen states which one you chose. It closes by naming what to do next: run gatto, then /model gemma-4-26b-a4b-it to use it.
Model setups
A model setup is a folder under ~\.gatto\models\ that names one
model and how to run it: where its file is, how much context to give it, how it should be sampled.
It is not the model itself; the weights can live anywhere.
The setup wizard writes your first one. After that:
/model: show which one is armed./model <name>: switch to another, without leaving the session.gatto model: add one, in its own terminal. This is where a.ggufyou already have on disk becomes a setup.
One setup can hold several files of the same model, one per quantization, with one of them in
use. /model quant lists them and marks the one in use;
/model quant <name> switches to another. When that model is the one
being served, gatto asks first. It says that the server restarts on the new file, and that the
conversation is read again before the next answer. /model quant rm <name>
forgets one. A second file arrives through gatto model:
pick the same model with a different file and it joins the setup you already have.
⚠ Switching model mid-session means the new model has to read the whole conversation before it can add to it. gatto warns you and asks first, because on a local model that is not free.
A setup's own file is profile.json inside its folder. Useful keys:
files the .gguf files this setup holds, one of them in use context how many tokens of conversation to allow gpu_layers how much of the model to put on the graphics card sampling temperature and friends mmproj the vision file, for models that can see images extra_args anything else to pass the engine llama_server a specific engine build, if this model needs one
Each entry in files is a path, an optional quant label, and
active. Exactly one entry is "active": true, and
gatto refuses to start a setup where none or two are.
Serving a model
A local model runs as a small server on your machine, and gatto talks to it over the loopback address. Nothing listens outside your computer.
gatto serve start <model> start it gatto serve start <model> --detach start it and return the prompt gatto serve status is it running, and with what gatto serve stop stop it
Letting gatto start it for you
Set "auto_serve": true in a model's setup and gatto starts the server
when a session needs it, instead of telling you to. This is the setting most people want; the wizard
offers it.
Moving the weights somewhere with more room
Model files are large and your system drive may not be where you want them. The weights are
wherever the active entry's path says. Move the file, update that one
line, and gatto follows. To change where new downloads land, set
weights_root in gatto.json.
Locking the server down
Set "api_key" in the setup and the server will refuse requests that do not
present it. Worth doing if you run other software on the same machine that scans local ports; not
necessary otherwise, since the server is already bound to loopback only.
Settings: gatto.json
One file, ~\.gatto\gatto.json, holding the things that are true for every
project.
{
"$schema": "./gatto.schema.json",
"endpoints": {
"local": {}
},
"default_endpoint": "local",
"defaults": {
"local": { "model": "my-model" }
},
"memory": { "enabled": true }
}
An endpoint is somewhere gatto can talk to a model. The local one is a server on your own
machine, and it needs no address: each model setup names its own port. You can add others: a hosted
API is an endpoint with a base_url and a key_env, the
name of the environment variable that holds its key, so the key itself never sits in this file. An
endpoint's models list is what /model offers on it,
and a launch with no -m and no saved default takes the first one. An
extension can add an endpoint too (writing one shows how), and
default_endpoint can name it. gatto is local-first, and it does not stop
you.
defaults holds what you chose, per endpoint: the
model a launch takes when neither -m nor the role
names one, and the effort saved for each model. d in
the /model list writes the first, and a level typed after
/effort writes the second.
default_role names the role a bare gatto runs;
without it that is the generalist, and a name with no file in roles\ stops
the launch with the list of roles. wild set to true
starts every session in wild mode, and /safe turns it off for one session.
If this file will not parse, gatto doctor says so and every check that
depends on it reports cannot determine rather than guessing. Fix this one first; the rest
usually follow.
⚠ A project cannot override these. gatto deliberately does not read settings from the folder you opened, and doctor checks that no folder on the way up is trying to.
Every setting
The first key of a fresh gatto.json is
"$schema": "./gatto.schema.json", and that file sits beside it. gatto rewrites
it on every launch, so it always describes the version you are running, and an editor that reads it
will complete these keys and flag a typo as you type. The table below is generated from the same file.
| key | accepts | default | what it does |
|---|---|---|---|
endpoints | object | every place gatto can talk to a model. each key names one endpoint. | |
endpoints.<name>.base_url | string | the server address, an absolute http or https url. only the endpoint named local may omit it. | |
endpoints.<name>.key_env | string | name of the environment variable holding the api key. gatto reads the variable, never the key itself. | |
endpoints.<name>.context | integer | context window in tokens, used as the budget for this endpoint. | |
endpoints.<name>.thinking | object | per level request fields for a model that exposes reasoning effort. each value is an object or null. | |
endpoints.<name>.models | array of string | the model names this endpoint offers. /model lists them, a launch with no -m and no saved default takes the first, and a model outside the list is refused. | |
default_endpoint | string | which endpoint gatto opens on. a key under endpoints, or the name of an endpoint an extension contributes; checked at launch. | |
default_model | string or null | older form of defaults.<default_endpoint>.model. gatto reads it as that and moves it there on its next write. | |
defaults | object | what was chosen per endpoint. each key names an endpoint; an entry for an endpoint that no longer exists is ignored. | |
defaults.<name>.model | string or null | the model a launch on this endpoint takes when -m and the role name none. | |
defaults.<name>.effort | object | the effort saved per model on this endpoint, a level name per model id. | |
llama_server | string | path to the llama-server executable that gatto serve starts. | |
context_files | object | which project notes gatto reads at launch. | |
context_files.compat | boolean | false | also read other harnesses context files, not only GATTO.md. |
context_files.home | boolean | true | read the GATTO.md in your gatto folder as the first layer, under any project file. |
theme | dark | light | auto | "auto" | colour palette. auto probes the terminal background. |
glyphs | auto | unicode | ascii | "auto" | which glyph vocabulary to draw. auto reads the host: unicode on Windows Terminal and VS Code, ascii on a legacy console with no glyph for the marks. |
reasoning | collapsed | expanded | "collapsed" | how reasoning is displayed. collapsed streams then folds to one row, expanded stays open. |
regions (deprecated) | any | accepted and ignored. the display mode it selected no longer exists, and gatto still loads a file that carries it. | |
search | object | which providers web_search uses, and their settings. listing tavily requires search.tavily.apiKey, and listing searxng requires search.searxng.url, or gatto refuses to start. | |
search.providers | array of ddg | tavily | searxng | ["ddg"] | the provider chain, tried in order. a provider succeeds when it returns at least one result. |
search.tavily | object | settings for the tavily provider. | |
search.tavily.apiKey | string | your tavily api key, stored in this file as text. | |
search.searxng | object | settings for a searxng instance. | |
search.searxng.url | string | the instance address, an absolute http or https url. | |
weights_root | string | the folder new model files are fetched into, and the folder gatto scans for gguf files that have no model profile yet. | |
think | on | off | session default for a model whose reasoning is a switch. absent leaves the server default. | |
alt_screen | boolean | true | use the alternate screen. false keeps gatto on the main screen and in native scrollback. |
dump_on_exit | boolean | false | print the whole transcript to the main screen when gatto exits. |
stop_server_on_exit | boolean | false | stop llama-server when you leave gatto with /quit or with Ctrl+C. closing the window does not stop it. leave this off when two gatto windows use one server, because the first window to quit stops the server for both. |
mouse | boolean | true | capture the mouse for wheel scrolling and click to expand. off when alt_screen is false. |
wheel_lines | integer | 3 | lines scrolled per wheel notch. |
copy_on_select | boolean | false | copy a mouse selection to the clipboard when the drag ends. |
auto_compact | number or false | 0.8 | when to compact the conversation, as a fraction of the context window. false turns it off. |
deny_reason | boolean | false | after denying a tool call, offer to type a reason the model will read. |
memory | object | the memory files gatto may write and recall. | |
memory.enabled | boolean | true | allow memory. false stops memory_write and keeps memory out of the prompt. |
memory.index_budget | integer | tokens the memory index may use. unset lets gatto derive it from the context window. | |
update_check | boolean | may gatto ask github whether a newer release exists. absent means never asked, and nothing is sent. | |
extensions | object | settings for installed extensions, one object per extension name. gatto checks only that each value is an object; the extension reads its own keys. |
read from gatto@344993bb
Web search is the one setting whose shape is worth seeing whole. Providers are tried in order, and a provider that is listed must carry its own settings or gatto refuses to start:
{
"search": {
"providers": ["ddg", "tavily", "searxng"],
"tavily": { "apiKey": "tvly-..." },
"searxng": { "url": "https://searx.example.org" }
}
}
Extensions
An extension is a C# script that gives gatto a new tool. They live in
~\.gatto\extensions\, are compiled at launch, and come from your folder
only, never from the project you have open.
- Install: save the
.csxfile into that folder, keeping its name, and restart gatto. A one-command install is coming. - Remove: delete the file. Nothing else remembers it.
- Check:
gatto doctorcompiles every script and reports the ones that fail;/toolsshows what a session actually armed. - Guidance: an extension may also add one line of standing guidance to the session, shown
under
/toolsbeneath the tools it came with. It arrives with the extension and goes when you delete the file.
The extensions page lists the ones that ship, with their full source; writing one documents the host API.
Why an edited copy can behave differently
Some bundled extensions are trusted with slightly more access than a script you wrote yourself;
ask_user is one, which is why it can interrupt you without asking
permission first. That trust is not attached to the name; it is attached to the exact contents of
the file, checked against the copy compiled into gatto.
So: change one byte and it becomes an ordinary script. It still runs, and it still works, but it loses the extra access and starts asking permission like anything else. Rename it, or nest it in a folder of its own, and the same thing happens. ⚠ This is worth knowing because nothing errors when it happens: the tool simply does a little less than it used to, and the reason is not on screen.
The web tools
Two of the bundled extensions let gatto reach the internet:
web_search looks things up, and web_fetch reads a
page and hands back its text.
⚠ These are the only tools that send anything off your machine, and they are
permission-gated per project like any other command, even though they ship with gatto. If you
never say yes, nothing leaves. Delete
web_search.csx and the capability is gone entirely.
Where the results come from
Searching tries a chain of providers in order and stops at the first that returns anything. The
default needs no account. Others can be configured in gatto.json under a
"search" section; the supported names are
ddg, tavily and
searxng; the last two want a key or a server address of your own.
When the citations check is on, gatto keeps a record of every page it fetched during a session, beside that session's transcript.
Where everything lives
All of it is under ~\.gatto\, and all of it is plain files you can read
and edit.
~\.gatto\
gatto.json settings: endpoints, the default model, memory on or off
GATTO.md notes read at the start of every session, everywhere
models\ one folder per model setup, each with a profile.json
roles\ generalist.json, coder.json, oracle.json, and yours
extensions\ .csx scripts, compiled at launch
sessions\ one transcript per conversation
<your project>\
GATTO.md notes for this project
.gatto\
permissions.json what you have granted here
memory\ facts gatto has banked about this project
Two things follow from that shape, and they are the whole design:
- What gatto can do is decided in your home folder. Tools, roles, models: a project you open cannot add to any of them.
- What gatto has learned is decided per project. Permissions and memory live with the work they belong to, and do not follow you to the next folder.
To remove gatto entirely, delete this folder and the executable. See uninstalling.