(^· ·^)⟆ gatto · an AI assistant that runs on your own PC

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.md the 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 i is 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 also cudart-llama-bin-win-cuda-12.4-x64.zip from 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 command or lists subcommands: that is a different program with a similar name. Look for llama-server.exe itself.
  • 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 --continue resumes the last conversation in this folder.
  • gatto --continue <id> resumes a particular one.
  • /new starts 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 file
  • write_file: write a new one
  • edit_file: change part of one, leaving the rest alone
  • glob: find files by name
  • grep: search inside files
  • shell: 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 &lt;!--. 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 first writes 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 .gguf you 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.

keyacceptsdefaultwhat it does
endpointsobjectevery place gatto can talk to a model. each key names one endpoint.
endpoints.<name>.base_urlstringthe server address, an absolute http or https url. only the endpoint named local may omit it.
endpoints.<name>.key_envstringname of the environment variable holding the api key. gatto reads the variable, never the key itself.
endpoints.<name>.contextintegercontext window in tokens, used as the budget for this endpoint.
endpoints.<name>.thinkingobjectper level request fields for a model that exposes reasoning effort. each value is an object or null.
endpoints.<name>.modelsarray of stringthe 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_endpointstringwhich endpoint gatto opens on. a key under endpoints, or the name of an endpoint an extension contributes; checked at launch.
default_modelstring or nullolder form of defaults.<default_endpoint>.model. gatto reads it as that and moves it there on its next write.
defaultsobjectwhat was chosen per endpoint. each key names an endpoint; an entry for an endpoint that no longer exists is ignored.
defaults.<name>.modelstring or nullthe model a launch on this endpoint takes when -m and the role name none.
defaults.<name>.effortobjectthe effort saved per model on this endpoint, a level name per model id.
llama_serverstringpath to the llama-server executable that gatto serve starts.
context_filesobjectwhich project notes gatto reads at launch.
context_files.compatbooleanfalsealso read other harnesses context files, not only GATTO.md.
context_files.homebooleantrueread the GATTO.md in your gatto folder as the first layer, under any project file.
themedark | light | auto"auto"colour palette. auto probes the terminal background.
glyphsauto | 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.
reasoningcollapsed | expanded"collapsed"how reasoning is displayed. collapsed streams then folds to one row, expanded stays open.
regions (deprecated)anyaccepted and ignored. the display mode it selected no longer exists, and gatto still loads a file that carries it.
searchobjectwhich 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.providersarray of ddg | tavily | searxng["ddg"]the provider chain, tried in order. a provider succeeds when it returns at least one result.
search.tavilyobjectsettings for the tavily provider.
search.tavily.apiKeystringyour tavily api key, stored in this file as text.
search.searxngobjectsettings for a searxng instance.
search.searxng.urlstringthe instance address, an absolute http or https url.
weights_rootstringthe folder new model files are fetched into, and the folder gatto scans for gguf files that have no model profile yet.
thinkon | offsession default for a model whose reasoning is a switch. absent leaves the server default.
alt_screenbooleantrueuse the alternate screen. false keeps gatto on the main screen and in native scrollback.
dump_on_exitbooleanfalseprint the whole transcript to the main screen when gatto exits.
stop_server_on_exitbooleanfalsestop 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.
mousebooleantruecapture the mouse for wheel scrolling and click to expand. off when alt_screen is false.
wheel_linesinteger3lines scrolled per wheel notch.
copy_on_selectbooleanfalsecopy a mouse selection to the clipboard when the drag ends.
auto_compactnumber or false0.8when to compact the conversation, as a fraction of the context window. false turns it off.
deny_reasonbooleanfalseafter denying a tool call, offer to type a reason the model will read.
memoryobjectthe memory files gatto may write and recall.
memory.enabledbooleantrueallow memory. false stops memory_write and keeps memory out of the prompt.
memory.index_budgetintegertokens the memory index may use. unset lets gatto derive it from the context window.
update_checkbooleanmay gatto ask github whether a newer release exists. absent means never asked, and nothing is sent.
extensionsobjectsettings 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 .csx file 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 doctor compiles every script and reports the ones that fail; /tools shows what a session actually armed.
  • Guidance: an extension may also add one line of standing guidance to the session, shown under /tools beneath 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.

GGitHub XX BBluesky MMastodon RReddit Windows 10 / 11 GPL-3.0
(^· ·^)⟆   zzz

nothing here yet: a game goes in this space

Close gatto.computer
(^· ·^)⟆

Are you sure you want to close this window?

It's now safe to close
this tab.
…or come back.