The first launch picks a model
Run shoal in a terminal with nothing configured and it asks before it starts.
When the binary is loose, it offers to install itself first. Then it lists the
models it found on this machine, numbered, with their sizes:
models on this machine:
1 gpt-oss-20b-MXFP4.gguf 12.0 GB
moor which model? [1]
The choice is saved as your user-wide default, so every launch after this one
runs on it without asking. Change it any time with shoal config set model <name>. When the machine has no models at all, the wizard prints where to get
llama.cpp and where to put a GGUF, then stops.
The wizard only runs when somebody is there to answer it, meaning an
interactive terminal with no model already resolved and no -p prompt.
Starting unmoored is a real state
Every other launch with nothing configured starts anyway. No dock is detected and no server starts. The agent runs on a provider that refuses every model call with one sentence:
no model is moored: pick one from the mooring form, or pass --model
Nothing crashes. The session is live, commands work, and the fleet lists. This is the state a piped or headless launch lands in, and the message names the flag that fixes it.
The terminal keeps every finished line
Shoal does not take over the screen. A small live region at the bottom holds the status lines, the input box, and any approval prompt. Everything that finishes is printed above it into the terminal’s own scrollback, so completed output has native selection, native search, and it is still there after you quit.
A turn moves through phases and each one gets a live line while it runs. The lines say sending to model, planning tools, inferencing with its loop number, and delegating. A tool call opens its own line and, when it returns, that line is replaced by a block showing what went in and what came out. A sub-agent’s work renders indented under the parent. The turn ends with elapsed time and a step count.
When stdin is not a terminal, the surface degrades to plain lines. Each input
line is one turn, streamed text prints as it arrives, and write and shell tools
stay denied unless the run was started with --auto-approve.
Approvals take a single key
Before a write, an edit, or a patch, Shoal shows the diff it computed from the tool arguments and the file on disk, then waits for one key.
| Key | Effect |
|---|---|
y | Allow this call |
a | Allow this tool for the rest of the session |
n | Deny this call |
ESC, Ctrl+C, and Enter also deny. Any other key is ignored while the prompt is up. A tool a sub-agent asks for comes to the same prompt. A denied call never runs, and the transcript records the denial in place of the call.
Enter steers and ESC interrupts
Typing while a turn is running and pressing Enter queues your text for the loop’s next iteration instead of starting a new turn. The interjection is printed into the transcript so it stays visible in the history. ESC interrupts the running turn. Ctrl+C is ignored mid-turn and quits when idle, and Ctrl+D quits on an empty input line. The up and down arrows cycle earlier input.
/help prints the slash command menu and /shortcuts prints the key list.
Both read from the same tables the reference pages on this site are built from.
Sessions and servers outlive a run
Every message is stored as it happens, and a session is titled from your first
line. shoal sessions lists what is stored, newest first. /sessions lists
the recent ones from inside a session. Pick one back up with --resume <id> at
launch or /resume <id> in the session, and an unambiguous id prefix is enough.
A persistent server means the model loads once instead of once per run:
shoal up --model <path> # start a server and leave it running
shoal --model <path> # this run adopts the healthy server
shoal down # the deliberate stop
A run that finds a healthy server on the port uses it and leaves it running on exit. A run that finds nothing spawns its own server and stops it when the session ends. The server binds to 127.0.0.1 and is never exposed to the network.