Goose Code CLI Guide
A coding agent from your terminal. The CLI runs on the same core (runOpenAiAgent) as the desktop app: the same loop, the same tool set, the same skills and subagents, the same session files. Only the shell differs - a terminal instead of a window.
The command is called goosecode (short alias - goose). The standalone binary (goose-windows-x64.exe / goose-linux-x64 / goose-macos-arm64) runs without Node/Bun - rename it to whatever suits you. The examples below use goose. From source (dev): bun run cli <args> or bun src/cli/index.ts <args>.
Quick start#
The general form: a command (defaults to run), any options, and an optional prompt. Give a prompt to run one task; omit it to open the interactive REPL.
goose [command] [options] ["<prompt>"]# Interactive session in the current folder (full-screen UI)
goose
# One-off task: streams the answer and exits
goose "add a dark-mode toggle to the settings page"
# Headless (for scripts/CI): -p / --print
goose -p "explain what src/cli/index.ts does" > notes.md
# Context via stdin
cat build.log | goose -p "why did this build fail?"
# Continue the previous session
goose -c "now write tests for that change"With no prompt and a terminal attached, an interactive session starts (the full-screen UI by default, or the line-based REPL with --no-ink). With a prompt (an argument and/or stdin) a single non-interactive turn runs instead. See Interactive vs non-interactive for the full breakdown.
Exit codes: 0 - success; 1 - agent error, unknown flag, missing prompt, or missing key. This is what to rely on in CI.
Interactive vs non-interactive#
The CLI picks one of two modes from the way you launch it, and they behave very differently: one keeps a conversation open, the other runs a single task and exits.
| Interactive | Non-interactive (headless) | |
|---|---|---|
| Starts when | No prompt and a terminal (TTY) is attached - just goose. | A prompt is given (argument and/or stdin), or -p is passed. |
| What happens | Opens a session you talk to turn after turn; it stays open until you leave. | Runs a single turn, streams the answer to stdout, then exits. |
| Interface | Full-screen terminal UI by default; --no-ink switches to the plain line-based REPL. | No UI - just the streamed output (colors auto-off outside a TTY). |
| Slash commands | Yes - /help, /new, /model, and the rest. | No - it is one shot. |
| Output | Always the human-readable view. | Pick with --output-format: text, json, or stream-json. |
| Best for | Coding by hand in the terminal. | Scripts, pipes and CI. |
# Interactive: the full-screen UI (default)
goose
# Interactive: the classic line-based REPL instead of the full-screen UI
goose --no-ink
# Non-interactive: one task, streamed to stdout, then exit
goose -p "explain what src/cli/index.ts does"
# Non-interactive is also implied by any prompt (even without -p)
goose "add a dark-mode toggle to the settings page"The -p / --print flag forces non-interactive mode even with no prompt in the arguments - useful when all the input arrives on a pipe.
Authentication and keys#
The CLI is account-only - the same as the desktop app.
A Goose Code key
A gsk_live_… key is created in your account - on the goosecode.org website or in the desktop app (Settings → API Keys). It authenticates your account, usage bills against your subscription (just like in the app), and it's what unlocks the server-mediated tools - web search, page fetching, image analysis and generation (see Which tools are available).
export GOOSE_API_KEY=gsk_live_XXXXXXXXXXXXXXXXXXXX
goose -p "fix the failing test in src/auth"
# or once, as a flag
goose --api-key gsk_live_XXXX -p "explain this repo"Precedence: --api-key <token> → GOOSE_API_KEY (env). A value beginning with gsk_live_ always goes to the Goose Code proxy.
eval build (meant for sandbox evals where the harness measures the model on its own credentials). In a normal user build OPENAI_API_KEY / OPENROUTER_API_KEY are ignored.The run command - the agent#
Runs the agent on a prompt. run is the default command, so goose "prompt" is equivalent to goose run "prompt". The prompt may be an argument, piped in on stdin, or both.
goose [run] [options] ["<prompt>"]Options:
| Option | Purpose |
|---|---|
-p, --print | Headless (non-interactive): stream the answer and exit. The prompt can be piped in. |
-m, --model <id> | Model: goose-ai (default) · auto · goose-local. |
-d, --dir <path> | Working directory (defaults to the current one). |
-c, --continue | Continue the most recent session. |
-r, --resume <id> | Resume a session by id. |
--max-effort | Force the strongest tier and highest reasoning effort. |
--verbose | Show the agent's thinking. |
--output-format <fmt> | text (default) · json · stream-json. |
--max-turns <n> | Cap the number of agent turns (only with -p). |
--api-key <token> | A Goose Code account key (or a provider key in an eval build). |
-f, --file <path> | Attach a file to the prompt. Repeatable. |
-s, --skill <name> | Load a skill by name before the turn. Repeatable. |
--no-code-index | Don't build the semantic code index for this run. |
--no-session-persistence | Run in memory - the session isn't saved and can't be resumed. |
--no-ink | Interactive only: use the plain line-based REPL instead of the default full-screen UI. |
Models
goose-ai(default) - the family via account/proxy. The main path.auto- the OpenAI tier chain. A provider path, so in a public build it needs an account (a BYO OpenAI key works only in an eval build).goose-local- an offline mock agent. No key needed, deterministic output. Good for checking the pipeline, scripts and tests.
# Strongest tier + highest reasoning on a hard refactor
goose -p -m auto --max-effort "refactor the auth module to remove the callback hell"
# Offline check that the CLI works at all
goose -p -m goose-local "hello"Attach files
--file puts a file into the message context. The core detects the type itself - text, PDF, DOCX, XLSX, an image (images need an account key). A missing path or a directory is an error at startup (better to fail than to silently answer about a file the agent never saw).
goose -p -f error.log -f src/server.ts "why does the server 500 on startup?"
goose -p --file spec.pdf "summarise the API contract in this spec"An attachment is spent on the first turn (like the app's composer), not glued onto every subsequent one.
Load a skill
--skill loads a skill by name before the turn begins. See the available ones with goose skills.
goose -p -s code-review "review my staged changes"
goose -s react-app "scaffold a settings page with a dark-mode toggle"A one-off run that leaves no trace
# Writes nothing to the data directory; cannot be resumed
goose -p --no-session-persistence "one-off question - don't save it"Interrupt
Ctrl-C stops the current turn (the session is kept). A second Ctrl-C at an idle REPL prompt exits.
Interactive session#
Starts when there is no prompt and a terminal is attached: just goose. By default it is a full-screen terminal UI - a composer, live streaming, and a status line. Prefer a classic line-based prompt? Add --no-ink. Both accept the same slash commands:
/help show help
/new start a new session
/sessions list recent sessions
/rm [id] delete a session (default: the current one)
/model <id> switch model (auto | goose-ai | goose-local)
/effort toggle max-effort
/clear clear the screen
/exit, /quit leaveAny other /name is treated as a skill invocation of that name (the same as goose skills). For example /code-review inside the REPL runs the code-review skill.
To an agent question (AskUserQuestion) in the REPL you reply with the option number or your own text.
Output formats and automation#
--output-format controls what goes to stdout.
text (default)
A human-readable rendering: assistant text, tool cards, diffs.
json - a single final object
When the turn finishes, exactly one object is printed - the answer and the totals. Handy for a script that wants the result, not a play-by-play.
goose -p -m auto --output-format json "what does src/cli/index.ts export?" | jq -r .resultObject shape:
{
"type": "result",
"is_error": false,
"session_id": "…",
"num_turns": 3,
"result": "…answer text…",
"usage": { "turns": 3, "inputTokens": 1200, "outputTokens": 340, "…": "…" }
}The usage and error fields are present only when there's something to show (the offline goose-local model, for instance, has no usage). The keys type, is_error, session_id, num_turns, result are always present.
stream-json - an NDJSON stream
A line-by-line stream of events as they happen - one JSON object per line. This is the programmatic contract the eval harness parses.
goose -p -m auto --output-format stream-json "fix the bug" \
| jq -c 'select(.kind=="block")'Event kinds (the kind field): message-start, block, usage, error, message-end.
The --json flag is a legacy alias for --output-format stream-json (hidden from --help, but still working; existing scripts and the harness depend on it).
Cap the number of turns
# Don't let an unattended run "keep going until it decides to stop"
goose -p --max-turns 8 "investigate and fix the flaky test"--max-turns counts main-loop turns (not subagent calls) and only applies in headless mode.
Fail a CI step on an agent error
# is_error → a non-zero exit code
goose -p --output-format json "run the tests and fix any failure" \
| jq -e '.is_error | not' > /dev/null || exit 1Sessions#
Lists and deletes saved sessions, which are shared with the app (the same data directory).
goose sessions [list | rm <id…>]list (the default, can be omitted) prints recent sessions; rm <id…> deletes one or more by id. To reopen a session, use -c (latest) or -r <id> on run.
# List (list is the default command, can be omitted)
goose sessions
goose sessions list
# Delete one or more by id
goose sessions rm 8d4e82c9-801d-4110-ad5c-15094f2291cd
goose sessions rm <id1> <id2> <id3>
# Continue the latest / resume a specific one
goose -c "and add a test as well"
goose -r 8d4e82c9-801d-4110-ad5c-15094f2291cd "finish this PR"Deleting an unknown id is an error (exit 1), not a silent success.
Skills#
Skills are instruction packs, compatible with the Claude Code format. The CLI sees them from several layers (built-ins + ~/.claude/skills/ + <data-dir>/skills/ + <cwd>/.claude/skills/ + <cwd>/.goose/skills/).
goose skills [--json]Lists the skills visible from the current folder; --json prints them machine-readably. Load one for a run with -s <name>.
# What's available from this folder
goose skills
# Machine-readable
goose skills --json
# Use one in a run
goose -p -s code-review "review the diff on this branch"In the REPL a skill is invoked as /skill-name [args].
Utility commands#
| Command | What it does |
|---|---|
goose index [-d dir] [--json] | Build the code index and print stats. |
goose doctor | Check the environment: runtime, ripgrep, tree-sitter, data dir, flags. |
goose open [-d dir] | Launch the desktop app (needs Electron; not in the standalone binary). |
Grep/Glob and the Run-command analyzer), not a CLI utility belt. Claude Code and Codex are built the same way. If you want a raw grep, you already have rg.Examples:
# Build the code index and print stats
goose index
goose index -d src --json
# Check the environment (runtime, ripgrep, tree-sitter, data-dir, flags)
goose doctor
# Launch the desktop app (needs Electron; not available in the standalone exe)
goose open -d ./my-projectExample doctor output:
✓ runtime bun 1.3.14
✓ electron …/node_modules/electron/dist/electron.exe
✓ ripgrep …/@vscode/ripgrep-…/rg.exe
✓ ts runtime …/web-tree-sitter/tree-sitter.wasm
✓ bash grammar …/tree-sitter-bash/tree-sitter-bash.wasm
✓ shell parser tree-sitter
✓ dist build …/dist
✓ data dir …/goose-code
✓ workspace /path/to/project (main)
flags: devtools, telemetry, shell-analysis, context-search, code-index, evalEnvironment variables#
Keys and access (public build)
| Variable | Effect |
|---|---|
GOOSE_API_KEY | A Goose Code account key (gsk_live_…). The only key that works in a public build. |
GOOSE_PROXY_TOKEN_FILE | Path to an account-token file; re-read on every request (a long run never sends a stale token). |
GOOSE_PROXY_TOKEN | A static account token. |
GOOSE_PROXY_BASE_URL | Inference proxy base (default https://api.goosecode.org/v1). |
GOOSE_PROXY_TOOLS_URL / GOOSE_TOOLS_BASE_URL | Web-tools base (default https://api.goosecode.org/tools). |
BYO provider keys - eval build only
Effective only if the build carries the eval flag (bun run eval:binary). Ignored in a public build.
| Variable | Effect |
|---|---|
OPENROUTER_API_KEY | OpenRouter key for goose-ai (eval). |
OPENAI_API_KEY | OpenAI key for auto (eval). |
OPENROUTER_BASE_URL / OPENAI_BASE_URL | Alternate provider endpoints. |
Behavior and output
| Variable | Effect |
|---|---|
NO_COLOR | Disable ANSI colors (also auto-off when stdout is not a TTY). |
GOOSE_MODEL_FAMILY | Model family: deepseek → DeepSeek; otherwise MiMo (default). |
GOOSE_NO_PLAN=1 | Disable the planning pass and the parallel subagent fan-out. |
GOOSE_PROMPT | Base-prompt A/B arm: opencode / goose; otherwise v2 (production). |
GOOSE_WASM_DIR | Explicit tree-sitter grammar directory (for container runs). |
Where things live#
The data directory is shared with the app:
- Windows:
%APPDATA%\goose-code - macOS:
~/Library/Application Support/goose-code - Linux:
$XDG_CONFIG_HOME/goose-code(usually~/.config/goose-code)
Inside: sessions/ (one file per session), settings.json (shared settings), code-index/ (index cache), skills/ (global skills). The exact path is shown by goose doctor (the data dir line).
Which tools are available in the CLI#
The agent sees the same tool set as the app, minus those that physically cannot run in the current process. Only workable tools are offered to the model - so it doesn't spend a turn on a call that's bound to fail.
| Tools | When available |
|---|---|
| Read, Write, Edit, Bash, PowerShell, Grep, Glob, Skill, Agent, TodoWrite, AskUserQuestion, documents (pdf/xlsx/docx) | Always |
| outline, symbols, deps (code index) | Index enabled (no --no-code-index, build ships the grammars) |
| WebSearch, WebFetch, analyze_image, generate_image | Account credentials present (a gsk_live_… key) |
| verify_web | Desktop app only (needs a browser) |
Practical upshot: on a Goose Code key everything is available except verify_web. (In an eval build on a BYO provider key, web/vision drop out - they need an account - but the full coding tool set stays.)
Docker / CI#
Use a glibc base image (e.g. debian) - bun-linux-x64 is not built for musl (Alpine).
docker run --rm \
-e GOOSE_API_KEY \
-v "$PWD:/work" -w /work \
debian:stable-slim \
./goose-linux-x64 -p "fix the failing test"The binary extracts its embedded ripgrep into the data directory on first run - no external ripgrep is needed in the container.
An example CI step that fails on an agent error:
goose -p --max-turns 12 --output-format json "make the test suite pass" \
| tee result.json | jq -e '.is_error | not' > /dev/nullTroubleshooting#
export GOOSE_API_KEY=gsk_live_…, or pass --api-key. Quick check without a key: -m goose-local. A raw OpenAI/OpenRouter key won't do in a public build - only in an eval build.gsk_live_…).--no-code-index, or a build without grammars). The agent works fully via Grep/Glob/Read.NO_COLOR=1 (or just write to a pipe/file - colors turn off automatically outside a TTY).Ready to run it in your terminal?
Grab the standalone binary or the desktop app - no API keys required.