This page is generated from the binary. Each command below, every flag,
every default, and every line of help is read out of the program at
version 0.32.0 rather than written beside it, so a reference that
disagrees with what runs on your machine is a build failure rather than
a page nobody noticed.
The extension runs these for you. It spawns shoal proto and
talks to it, so the commands here are what you reach for when you set
the machine up, check what it found, or manage a server outside the
editor.
The app window is shoal desktop. The rest of these commands
are what you reach for when you set the machine up, check what it
found, or manage a server that outlives a single window.
shoal
Shoal - a local-first coding agent
Shoal is a coding agent that runs on your own hardware. It manages the
inference server itself, keeps history stable for the server's prefix
cache, asks before writes and shell commands, and delegates subtasks
to fresh-context sub-agents. Cloud APIs are optional, never required.
Install once: shoal setup. Save a default model: shoal config set
model <name>. After that, a bare shoal in any terminal is enough.
Server lifecycle: shoal up, shoal down, shoal doctor, shoal models.
Docks (where models tie up):
- mlx: Apple Silicon via mlx_lm.server (macOS only)
- llamacpp: NVIDIA CUDA / Metal via llama-server (all platforms)
- remote: an OpenAI-compatible server you run, here or on another box
- anthropic: Anthropic's API, reached by a mooring record with your key
- openai: OpenAI's API, reached by a mooring record with your key
Those options except --version are persistent: --auto-approve, --dock, --endpoint, --hitl, --index, --model, --prompt, --resume can
be given to any command below as well, not only to a bare
shoal.
shoal audit
What a session touched, read and produced
audit reads the row log: one append-only record per tool call, per
agent loop and per model call, written under the data directory and
outliving the session that wrote it.
shoal audit index every session in the log
shoal audit --session <id> one session
shoal audit --day 2026-09-01 one day
shoal audit --json the same index as one JSON object
shoal audit --store where the log lives and what it costs
It is an index, not a transcript. It says which files were read,
written and failed, which calls were refused, what the model calls
cost, and how much of the window was in use. It does not carry tool
arguments or results: a row is a fact about a call, not a copy of it.
The log is on by default and shoal config set rowlog off stops it.
shoal berth
Run the agent loop here for a surface on another machine
berth runs the engine on this machine and listens for one surface to
drive it. The loop, the tools, and the workspace are here; a person
sitting at another machine runs "shoal connect" or "shoal desktop
--berth" and works in this tree.
The default listen address is 127.0.0.1, which reaches nothing but
this box. Reaching further is an address you type: --listen
0.0.0.0:7823 offers the berth to your network.
Every connection is authenticated and every connection is TLS. The
token lives in the secrets store under "berth_token";
--mint-token generates and saves one on the way up. The certificate is
self-signed and kept in `~/.shoal/berth/`, and the client pins its
fingerprint, which this command prints. Nothing dials out and there is
no relay: a berth behind NAT is reached through your own network.
A dropped connection does not stop the engine. Nobody attached for the
linger period does: --linger 0 keeps it up until you stop it.
shoal board
The metrics board: did the window hold, and what did it cost
board renders one session's telemetry from the row log: whether the
window held, what the tools did, what landed, and what it cost.
shoal board the last real session (eval runs skipped)
shoal board --session <id> a named session
shoal board --json the same board as one view-model JSON object
shoal board --with-eval fold in rows a benchmark run tagged eval
The spine is window-first: size, peak in use, drops, then activity,
and spend leads only where a mooring carries real prices. Rows the
eval runner tagged source=eval are excluded by default and the board
says how many it left out.
It reads the same log shoal audit reads. The audit is the trail and
never filters; the board is the view and says what it excluded.
shoal config
Show or set user-wide defaults (model, dock, endpoint, breakwater, trust, rowlog, memory, voyage)
config manages the user-wide defaults so shoal runs without flags.
shoal config show the current defaults
shoal config set model <name> set the default model
shoal config unset model clear a default
Keys: model, dock (mlx, llamacpp, remote), endpoint, breakwater, trust,
rowlog, memory, voyage.
breakwater is open or closed, and closed is the default even when the
key is unset. Closed means Shoal's own code reaches loopback and the
destinations a mooring names, and refuses every other one. Open takes
that wall down. shoal doctor prints which it is and what is named.
trust is the label a mooring gets when its own record carries none.
Unset is the default and means unlabelled, which is the full toolset,
exactly as before this key existed. Set it to unvetted to say you have
not vetted the models on this machine: every unlabelled mooring then
runs on the read-only toolset and says so when it starts. A record
labelled trusted still gets everything.
rowlog is on or off, and on is the default even when the key is unset.
On writes one JSON row per tool call, per agent loop and per model call
to an append-only log under the data directory, which is what answers
what a session touched, read and produced after the session itself is
gone. Off writes nothing at all. shoal audit reads it.
voyage is on or quiet, and on is the default even when the key is
unset. On, the status line above the composer narrates the turn as a
sea passage, phase by phase, each phase entered because its event
happened. Quiet gives the plain status words back.
memory is the directory the user-scope memory store lives in. Unset is
the default and means the memory folder under ~/.shoal, so a machine
that never sets it changes nothing. Set it to move the memory store
and only the memory store, for example to a folder another tool also
reads. SHOAL_HOME is the wrong tool for that: it moves the whole Shoal
home, secrets included, and while it is set it wins over this key. An
absolute path, or one starting with ~. shoal memory shows which rule
is deciding the path.
Precedence at launch: CLI flag, then the project's .shoal/config.json,
then these defaults.
unset clears one key. To clear the launch defaults together, so the
next launch is a first run: shoal reset-defaults. To walk the
first-run flow without clearing anything: shoal first-run.
shoal config set <key> <value>
Set a default
shoal config unset <key>
Clear a default
shoal connect <host[:port]>
Drive a Shoal engine running on another machine
connect speaks the protocol seam to a berth: an engine running
somewhere else, with its own workspace and its own filesystem. Events
come out on stdout as JSON lines and ops go in on stdin, exactly as
"shoal proto" does, so a client written for one drives the other.
The berth prints a certificate fingerprint when it starts. Pass it
with --fingerprint. A berth on this same machine needs none: its
certificate is on this disk and connect reads it.
The token comes from the environment (SHOAL_BERTH_TOKEN) or from
the secrets store, never from a flag, because a flag value is visible
in the process list.
Closing stdin leaves the remote loop running. To stop it, send a
shutdown op.
shoal desktop
Open Shoal as a desktop app window
desktop runs the engine and opens the Shoal web client in an
app-mode window on a loopback port. Closing the window exits Shoal;
the inference server follows the usual ownership rules (a server
started by shoal up persists, a session-owned one stops).
shoal doctor
Check platform, dependencies, and running services
Detect the host platform, verify the dependencies shoal needs
(including the llama-server security floor), and report which inference
servers are answering locally.
An inference server whose owning session is gone is stopped and
reported, so the memory it holds goes back to the machine. A server
started by shoal up records no owner and is never touched.
shoal down
Stop persistent inference servers
Stop every shoal-managed inference server and clear stale pid
records. A server shoal did not start is reported but left running.
shoal exec [prompt]
Run one prompt without a terminal and exit with a code
exec runs one prompt on this machine and exits. There is no terminal,
nothing listens on a socket, and no ops are read after launch: stdin is
at most the prompt.
The prompt comes from the argument, from --file, or from stdin, and
exactly one of the three. With --workflow the same text becomes the
workflow's argument instead.
Output modes:
text the final assistant text on stdout, notices on stderr
json one result document: final text, stop reason, spend, files
touched, and every action the ladder refused
stream every seam event as JSON lines on stdout, as it happens.
This is the mode to script against: the vocabulary is the
engine's own protocol, not a second schema
Exit codes:
0 the turn completed and nothing was refused
1 the flags or the prompt could not be read
2 the engine did not start
3 the turn ended in an error
4 the turn spent its whole tool call budget
5 the turn finished and the ladder refused at least one call
6 the run was interrupted
7 the input gate answered the prompt without starting a turn
Approvals cannot ask anybody here, so they resolve from a rung of the
autonomy ladder. The rungs are named after Shoal's own tool classes:
read runs from the read rung
reads a file or searches the tree
delegate runs from the read rung
hands work to a sub-agent, whose own calls come back through
this same table
plan runs from the write rung
accepts a decomposition plan
write runs from the write rung
writes to a file
exec runs from the exec rung
runs a shell command
hook runs from --unsafe-approve-all
calls an outside process a hook started
tool runs from --unsafe-approve-all
carries no classification, so nothing here knows what it
does
The floor is read, which is the default. A write-classified call at the
floor is refused and reported, never dropped in silence. Whether a call
needs approving at all is the engine's own decision (internal/
permissions), the same one every other client asks, so a shell command
Shoal already treats as read-only runs at the floor too.
shoal first-run
Replay the first-run flow without clearing anything
first-run walks the flow a new machine gets, on a machine that is
already set up.
Nothing is cleared. The model list opens on the default this machine
already has, so pressing Enter through it leaves everything as it was;
picking a different model saves that one, exactly as the first launch
would have.
This is the flow to reach when you want to SEE the first run. To make
the next launch a first run for real, which does clear what is saved:
shoal reset-defaults
On the windowed surfaces the same two acts are /first-run and
/reset-defaults, and the first is also the "Set up this machine again"
row at the bottom of the model picker.
shoal memory
Show where memory lives and what it holds
memory shows the two stores a session in this directory would read:
the project scope at .shoal/memory in the repository, and the user
scope, which is the memory folder under ~/.shoal unless the memory key
moves it (shoal config set memory <dir>) or SHOAL_HOME moves the whole
Shoal home. It says which rule decided the user path, how many records
each scope holds, which slugs the project scope overrides, and which
records carry a format newer than this build reads.
Read-only. Records are files, one fact each, in a published format, so
either folder can be opened in any editor.
shoal memory this directory's stores
shoal memory discover other harnesses' stores on this machine
shoal memory discover
Find other harnesses' memory stores on this machine, read-only
discover looks where other agent harnesses keep memory and reports
what is there and where: Claude Code's per-project stores, Gemini
CLI's memory file, the Goose and Windsurf memory folders, the folders
OpenCode, Factory and Codex keep, and the neutral .agents location,
under the home directory and the current directory. Every location it
looked at is printed, found or not.
It reads names, counts, and the names of frontmatter keys. It never
reads a record's text, never shows one to a model, and never copies
one into Shoal's own store. Import is not built: it needs opt-in per
source and a review of every record before recall can see it, because
a folder of files written by another tool is untrusted text, and
recall is the path that carries text into a prompt without a person
reading it first.
--json prints the same sweep as one document.
shoal models
List known models and recommend one for this hardware
Show what is on disk, the model registry with per-dock identifiers,
a hardware-aware recommendation, and what each model on disk says about
itself. A model already on disk that fits the memory budget is recommended
over a registry download. The sizing is a
heuristic (weights against a memory budget with KV headroom); any GGUF path
or MLX id outside the registry still works with --model.
Provenance is reported in three states and never two. What a GGUF header
says about its own name, publisher and licence is claimed: the header
travels with the file, so nothing here checked it. The path, the size and
the sha256 are verified, because this machine read them. Anything absent
is not stated, which is silence and not a finding.
--hash reads every model on disk and records its digest, so a later
listing can report it as verified. Nothing is fetched and nothing is
compared: the number is printed for you to compare against whatever the
publisher published.
shoal proto
Speak the protocol seam over stdio (JSON lines)
proto runs the engine as a child process for GUI clients: protocol
events stream out on stdout, one JSON object per line, and ops arrive
on stdin the same way. stdout is pure protocol; startup prints and
diagnostics go to stderr. Closing stdin shuts the engine down cleanly.
Approvals assume an interactive approver on the other end: tool calls
that need approval emit approval_requested events and wait for a
resolve_approval op. Pass --auto-approve to skip approvals entirely.
shoal reset-defaults
Clear the saved launch defaults, so the next launch is a first run
reset-defaults clears the user-wide launch defaults in one act:
model, dock and endpoint. The next launch then resolves no model and
meets the first-run condition, which is the terminal wizard on a
terminal and the launch portal on the windowed surfaces.
What it does not touch, and why:
breakwater, trust policy, not convenience. Unset already means
the wall is up, and clearing trust would widen
what an unlabelled mooring may do.
mooring records a record is something you wrote down. Forget
removes one, by name, from the mooring form or
/moor on a windowed surface. A record carrying
the main purpose supplies the launch on its
own, so this command names it when one still
does rather than deleting it for you.
the project config .shoal/config.json belongs to the repository,
not to this machine. It is reported, never
edited.
To clear one key instead of all of them, shoal config unset <key>. To
walk the first-run flow without clearing anything, shoal first-run.
shoal secret
Manage the secrets hooks authenticate with
secret manages the values a hook needs to authenticate, kept
outside every project and readable only by you.
shoal secret set <name> store a value, read from a prompt or stdin
shoal secret list list names and fingerprints, never values
shoal secret rm <name> remove one
Reference a secret from a hook's env in hooks.json as ${secret:NAME}.
It resolves when the hook process is spawned, into that process's
environment, and never into a prompt, a tool result, or a stored
session. A value that comes back out in a hook's output is replaced
with [redacted:NAME] before it reaches the model.
shoal secret list
List secret names and fingerprints
shoal secret rm <name>
Remove a secret
shoal secret set <name>
Store a secret, reading the value from a prompt or stdin
set reads the value from a prompt, or from stdin when it is piped.
The value is never taken as an argument: arguments are visible in
shell history and in the process list.
shoal secret set LINEAR_TOKEN
echo $TOKEN | shoal secret set LINEAR_TOKEN
shoal sessions
List and manage sessions
shoal setup
Install shoal as a program (uninstall with --uninstall)
setup installs the running binary as a per-user program:
- copies it to the user programs directory
- puts shoal on PATH, so any new terminal runs it by name
- registers it with the OS (Start Menu, Apps & features on Windows)
Re-running setup from a newer binary upgrades the install in place.
--uninstall reverses everything; session data and config are kept.
When no default model is saved yet, setup asks for one as part of
installing, so a bare shoal starts on every surface afterwards. The
same default can always be set or changed by hand:
shoal config set model <name>
shoal up
Start a persistent inference server
Start the inference server detached, so it outlives this command.
The model loads once; later shoal runs find the server healthy on the port
and use it instead of spawning their own. Stop it with shoal down.
The server binds to 127.0.0.1 only, never exposed to the network.
This reference matches Shoal 0.32.0.