On this page

Run Shoal

Command-line interface

Every Shoal entry point: interactive use, one-liners, scripts, stdin, formatting, diagnostics, completions, prompt tools, LSP, and MCP.

Status
Current implementation
For
Users and automation authors
On this page
  1. Synopsis
  2. Dispatch rules
  3. Evaluate a one-liner
  4. Run a script
  5. Read source from stdin
  6. Exit status
  7. Format source
  8. Run diagnostics
  9. Generate shell completions
  10. Inspect the prompt
  11. Start the language server
  12. Start the MCP bridge
  13. Companion binaries
  14. Environment used by the host

The shoal executable is both the language runner and the dispatcher for developer integrations. Its default is intentionally context-sensitive: no arguments starts the REPL when stdin is a terminal, but reads source from stdin when input is piped.

Synopsis🔗

shoal [OPTIONS] [SCRIPT [ARG ...]]

shoal -c SOURCE
shoal fmt [--check] [FILE ...]
shoal doctor [--json]
shoal completions <bash|zsh|fish>
shoal prompt <explain|bench|print> [--side SIDE] [--n N]
shoal lsp
shoal mcp

Global help and version:

shoal --help
shoal --version

Dispatch rules🔗

Evaluate a one-liner🔗

Use -c or --command when the source is part of the invocation:

shoal -c 'json.parse("{\"ready\":true}").ready'
shoal --command '(ls .).where(.type == "file").map(.name)'

Your invoking shell still interprets its own quoting before Shoal sees the string. Single-quote the outer source in Bash, Zsh, and similar shells when it contains Shoal double strings.

The non-interactive default is quiet: bare command output is shown, intermediate pure expression results are suppressed, and the final value is rendered. Set render.echo = "commands" to suppress even a final expression, or "all" to render every top-level result.

Run a script🔗

Pass a .shl file as the first non-option argument:

shoal scripts/release.shl staging --dry-run

The remaining arguments become a language-level args list of path-like values. Use normal value methods rather than expecting POSIX positional variables:

assert(!args.is_empty(), "usage: release.shl ENV")

let environment = args.first().str()

-- ends host option parsing when a script name or script argument could be mistaken for an option:

shoal -- ./-audit.shl --literal-argument

For runner-dispatched non-Shoal files inside the language, use run ./tool.py; see Reef environments.

Read source from stdin🔗

With no script and non-terminal stdin, Shoal reads the entire input as language source:

printf 'let x = 20\nx + 22\n' | shoal

This is source input, not data input to a program running inside Shoal. To give data to an external program, write a Shoal expression using feed.

Exit status🔗

Shoal uses a small host-level convention:

ConditionExit status
Successful evaluation0
Uncaught external cmd_failed with child status 1..=255that child status
Other uncaught evaluation/runtime error, or child status absent/out of range1
Parse error2
exit NN

An external process’s non-zero status raises cmd_failed in command-statement position. The non-interactive host propagates an attached status from 1 through 255; a signal-only failure, absent status, or out-of-range status falls back to 1. Capture an outcome when you need to inspect or deliberately transform that status before exiting.

let result = (^some-command)
if !result.ok { exit (result.status) }

Format source🔗

shoal fmt parses and formats Shoal source. With file arguments it rewrites them atomically:

shoal fmt src/main.shl scripts/release.shl

With no files it reads source from stdin and writes formatted source to stdout:

printf 'let   x=1\nx+1\n' | shoal fmt

Use check mode in CI. It makes no edits and exits 1 if any input would change:

shoal fmt --check scripts/*.shl

Run diagnostics🔗

shoal doctor reports host and Shoal integration health:

shoal doctor
shoal doctor --json

The JSON form is intended for automation. Reef has a separate scope-aware health check, reef doctor, which checks lock drift, orphaned entries, and ambient shadowing.

Generate shell completions🔗

Generate completion source for the supported host shell, then install it using that shell’s normal mechanism:

shoal completions bash > ~/.local/share/bash-completion/completions/shoal
shoal completions zsh > ~/.zfunc/_shoal
shoal completions fish > ~/.config/fish/completions/shoal.fish

These completions are for invoking the shoal executable from another shell. Shoal’s own REPL completion engine is configured under [completion] and understands language names, builtins, adapters, methods, variables, and PATH programs.

Inspect the prompt🔗

The prompt dispatcher can render a side, explain its modules and timing, or benchmark it:

shoal prompt print --side left
shoal prompt explain --side right
shoal prompt bench --side left --n 10000

Valid sides are left, right, continuation, and transient. --n applies to bench. Prompt rendering uses a frozen session snapshot so per-keystroke redraws perform no I/O; context collection happens between commands. See Configuration and prompt.

Start the language server🔗

shoal lsp

This launches the shoal-lsp stdio server. Configure an editor to start shoal lsp for Shoal source files. The subcommand looks up the companion executable through PATH, so shoal-lsp must be installed and discoverable there. The same rule applies to shoal mcp and its shoal-mcp companion.

Start the MCP bridge🔗

shoal mcp

This launches the stdio shoal-mcp bridge. It connects to a named kernel session and currently auto-starts shoal-kernel when the socket is unavailable. Set a non-empty SHOAL_NO_AUTOSTART to require an already-running kernel instead. Session, socket, and token options are available on the companion shoal-mcp binary and through SHOAL_SESSION, SHOAL_SOCKET, and SHOAL_TOKEN.

The MCP server is not simply a remote -c: it adds session-scoped references, plans and approvals, journal and task resources, notifications, and rendered PTY tools. Read Agents, kernel, and MCP before granting an agent access.

Companion binaries🔗

The workspace currently builds these public or operational executables:

BinaryRole
shoalREPL, language runner, and developer-command dispatcher
shoal-doctorstandalone diagnostics
shoal-historyhistory/journal utility
shoal-kernelpersistent multi-principal session host
shoal-mcpstdio MCP-to-kernel bridge
shoal-lsplanguage server
shoal-secretsecret-handling helper
shoal-tokentoken utility for authenticated sessions
shoal-landlock-helperLinux Landlock sandbox helper
shoal-sandbox-execmacOS sandbox-exec helper

The helpers are not all required for a basic local REPL. Install the complete workspace set when exercising kernel policy, agents, or platform sandboxing.

Environment used by the host🔗

Common host-level variables include:

VariableMeaning
XDG_CONFIG_HOMEuser configuration root; fallback ~/.config
XDG_STATE_HOMEhistory, journal, and jump-state root; fallback ~/.local/state
XDG_RUNTIME_DIRpreferred kernel socket root
NO_COLORdisable colored rendering by presence
PAGERpager fallback when render.paging = "auto"
SHOAL_NO_AUTOSTARTdisable MCP kernel auto-start when non-empty
SHOAL_CAPTURE_CAP_BYTESin-memory process capture cap
SHOAL_CAPTURE_SPILL_CAP_BYTESjournal/CAS spill cap

Configuration-specific SHOAL_* overrides are listed in Configuration and prompt. Treat any variable not documented there as an operational interface that may still move during the preview.

Type to search every guide navigate open esc close
Diagram