Command Line Interface for Roo Code - Run the Roo Code agent from the terminal without VSCode.
This CLI uses the @roo-code/vscode-shim package to provide a VSCode API compatibility layer, allowing the main Roo Code extension to run in a Node.js environment.
Install the Roo Code CLI with a single command:
curl -fsSL https://raw.githubusercontent.com/RooCodeInc/Roo-Code/main/apps/cli/install.sh | shRequirements:
- Node.js 20 or higher
- macOS Apple Silicon (M1/M2/M3/M4) or Linux x64
Custom installation directory:
ROO_INSTALL_DIR=/opt/roo-code ROO_BIN_DIR=/usr/local/bin curl -fsSL ... | shInstall a specific version:
ROO_VERSION=0.1.0 curl -fsSL https://raw.githubusercontent.com/RooCodeInc/Roo-Code/main/apps/cli/install.sh | shRe-run the install script to update to the latest version:
curl -fsSL https://raw.githubusercontent.com/RooCodeInc/Roo-Code/main/apps/cli/install.sh | shOr run:
zoo upgraderm -rf ~/.roo/cli ~/.local/bin/zooFor contributing or development:
# From the monorepo root.
pnpm install
# Build the main extension first.
pnpm --filter ./src bundle
# Build the CLI.
pnpm --filter @roo-code/cli buildBy default, the CLI auto-approves actions and runs in interactive TUI mode:
export OPENROUTER_API_KEY=sk-or-v1-...
zoo "What is this project?" -w ~/Documents/my-projectYou can also run without a prompt and enter it interactively in TUI mode:
zoo -w ~/Documents/my-projectIn interactive mode:
- Tool executions are auto-approved
- Commands are auto-approved
- Followup questions show suggestions with a 60-second timeout, then auto-select the first suggestion
- Browser and MCP actions are auto-approved
If you want manual approval prompts, enable approval-required mode:
zoo "Refactor the utils.ts file" --require-approval -w ~/Documents/my-projectIn approval-required mode:
- Tool, command, browser, and MCP actions prompt for yes/no approval
- Followup questions wait for manual input (no auto-timeout)
Use --print for non-interactive execution and machine-readable output:
# Prompt is required
zoo --print "Summarize this repository"
# Create a new task with a specific session ID (UUID)
zoo --print --create-with-session-id 018f7fc8-7c96-7f7c-98aa-2ec4ff7f6d87 "Summarize this repository"Danger: This profile gives the agent unrestricted authority to read and write inside or outside the workspace, modify protected configuration, execute any command, call any configured MCP tool, switch child modes, create subtasks, and accept completion. Run it only in an environment where the selected workspace, configuration, commands, MCP servers, and provider are fully trusted. It does not change VS Code or normal interactive CLI approval behavior.
Every new autonomous root starts in the effective orchestrator mode. A project .roomodes definition with the orchestrator slug overrides the global custom definition, which overrides the built-in definition, following normal Zoo Code precedence. --mode and --require-approval are rejected for autonomous roots. Child mode selection remains available to the existing new_task engine.
export OPENROUTER_API_KEY=sk-or-v1-...
zoo --autonomous --print \
--workspace /absolute/path/to/project \
--timeout 3600 \
--output-format stream-json \
"Implement the task and verify it"--workspace and --timeout are required. The workspace is resolved to its canonical filesystem path before activation. One process owns one root task tree; stdin multi-root stream mode is intentionally unavailable with this profile.
The real extension bundle remains the agent engine:
switch_modechanges the mode in the same task and preserves its conversation.new_taskpersists the parent and creates a fresh child context.- Child completion resumes the original parent with the child result and does not exit the process.
- Only an accepted
attempt_completionevent for the root task exits successfully. No implicit validation command is added. --session-idand--continueuse persisted task history. A resumed task retains its persisted mode and context; a newly created autonomous root always starts as Orchestrator.- The first
SIGINTorSIGTERMcooperatively aborts and settles persistence. A second signal force-terminates.
The selected workspace is used by the existing runtime to load .roomodes, .roo/mcp.json, .roo/rules*, legacy rule fallbacks, and root AGENTS.md/AGENT.md plus AGENTS.local.md. Global rules remain under ~/.roo/rules*. Shim-backed global custom modes and MCP settings use ~/.vscode-mock/global-storage/settings/custom_modes.yaml and ~/.vscode-mock/global-storage/settings/mcp_settings.json; project definitions take precedence where Zoo Code normally gives them precedence. Configuration is loaded before the first task starts. Long-running file-watcher reloads are not supported by the shim, so restart the process after changing these files.
Credentials must be supplied with --api-key or the provider environment variable. This standalone process does not inspect or import native VS Code settings databases, profiles, OAuth state, or encrypted SecretStorage. Its own persisted history and shim state can contain sensitive prompts, outputs, and settings and should be protected accordingly.
Headless filesystem reads/writes, protected-file edits, command execution through Execa, ripgrep search, configured MCP transports, mode switching, subtasks, persistence, and provider HTTP streams are supported. There is no interactive VS Code window. Editor selections/tabs, live diagnostics, visual diff UI, VS Code terminal shell integration, VS Code Language Models, native VS Code authentication/URI callbacks, clipboard UI, and reliable VS Code file-watcher semantics are unsupported. Required questions without a defined automatic answer terminate instead of selecting a suggestion or sending an empty answer.
Machine-readable modes emit exactly one final result with subtype: "terminal", state, exitCode, and the root task ID when available. Progress remains NDJSON in stream-json; extension debug logs do not go to stdout.
| State | Exit | Meaning |
|---|---|---|
completed |
0 | Accepted root completion after descendant resumption |
needs_input |
2 | A question has no defined autonomous answer |
provider_failed |
4 | Provider request failed or retry would require intervention |
tool_failed |
5 | A host/tool failure prevents continuation |
cancelled |
6 | Explicit non-signal cancellation |
cancelled |
130 | SIGINT after cooperative persistence settlement |
cancelled |
143 | SIGTERM after cooperative persistence settlement |
timed_out |
124 | Root-tree wall-clock timeout |
configuration_error |
78 | Invalid workspace, flags, credentials, or configuration |
crashed |
70 | Unexpected internal failure |
The non-billable process smoke starts a local fake OpenRouter-compatible server and disposable workspaces. It verifies custom Orchestrator/rule precedence, mode switching, delegation/resumption, questions, provider failure, timeout, cancellation, and parseable terminal output:
pnpm --filter ./src bundle
pnpm --filter @roo-code/cli build
pnpm --filter @roo-code/cli test:autonomous-processFor programmatic control (one process, multiple prompts), use --stdin-prompt-stream with --print.
Send NDJSON commands via stdin:
printf '{"command":"start","requestId":"1","prompt":"1+1=?"}\n' | zoo --print --stdin-prompt-stream --output-format stream-json
# Optional: provide taskId per start command
printf '{"command":"start","requestId":"1","taskId":"018f7fc8-7c96-7f7c-98aa-2ec4ff7f6d87","prompt":"1+1=?"}\n' | zoo --print --stdin-prompt-stream --output-format stream-jsonNormal CLI usage is login-free. Use --provider with your own API key, or set the provider environment variable directly.
Roo Code Router has been removed from the CLI. The remaining auth commands only help inspect or delete any legacy Roo auth token still stored from older releases:
# Check whether a legacy Roo auth token is still stored
zoo auth status
# Remove an old stored Roo auth token
zoo auth logoutIf you never used Roo Code Router, you can ignore this section entirely.
| Option | Description | Default |
|---|---|---|
[prompt] |
Your prompt (positional argument, optional) | None |
--prompt-file <path> |
Read prompt from a file instead of command line argument | None |
--create-with-session-id <session-id> |
Create a new task using the provided session ID (UUID) | None |
-w, --workspace <path> |
Workspace path to operate in | Current directory |
-p, --print |
Print response and exit (non-interactive mode) | false |
--stdin-prompt-stream |
Read NDJSON control commands from stdin (requires --print) |
false |
-e, --extension <path> |
Path to the extension bundle directory | Auto-detected |
-d, --debug |
Enable debug output (includes detailed debug information, prompts, paths, etc) | false |
-a, --require-approval |
Require manual approval before actions execute | false |
--autonomous |
Dangerous unrestricted headless Orchestrator profile (requires --print) |
false |
--timeout <seconds> |
Required wall-clock deadline for an autonomous root tree | None |
-k, --api-key <key> |
API key for the LLM provider | From env var |
--provider <provider> |
API provider (anthropic, openai-native, gemini, openrouter, vercel-ai-gateway) | openrouter |
--provider-base-url <url> |
OpenRouter-compatible endpoint override | Provider default |
-m, --model <model> |
Model to use | anthropic/claude-opus-4.6 |
--mode <mode> |
Mode to start in (code, architect, ask, debug, etc.) | code |
--terminal-shell <path> |
Absolute shell path for inline terminal command execution | Auto-detected shell |
-r, --reasoning-effort <effort> |
Reasoning effort level (unspecified, disabled, none, minimal, low, medium, high, xhigh) | medium |
--consecutive-mistake-limit <n> |
Consecutive error/repetition limit before guidance prompt (0 disables the limit) |
10 |
--ephemeral |
Run without persisting state (uses temporary storage) | false |
--oneshot |
Exit upon task completion | false |
--output-format <format> |
Output format with --print: text, json, or stream-json |
text |
| Command | Description |
|---|---|
zoo auth logout |
Clear a stored legacy Roo auth token |
zoo auth status |
Show legacy Roo token status |
The CLI will look for API keys in environment variables if not provided via --api-key:
| Provider | Environment Variable |
|---|---|
| anthropic | ANTHROPIC_API_KEY |
| openai-native | OPENAI_API_KEY |
| openrouter | OPENROUTER_API_KEY |
| gemini | GOOGLE_API_KEY |
| vercel-ai-gateway | VERCEL_AI_GATEWAY_API_KEY |
┌─────────────────┐
│ CLI Entry │
│ (index.ts) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ ExtensionHost │
│ (extension- │
│ host.ts) │
└────────┬────────┘
│
┌────┴────┐
│ │
▼ ▼
┌───────┐ ┌──────────┐
│vscode │ │Extension │
│-shim │ │ Bundle │
└───────┘ └──────────┘
-
CLI Entry Point (
index.ts): Parses command line arguments and initializes the ExtensionHost -
ExtensionHost (
extension-host.ts):- Creates a VSCode API mock using
@roo-code/vscode-shim - Intercepts
require('vscode')to return the mock - Loads and activates the extension bundle
- Manages bidirectional message flow
- Creates a VSCode API mock using
-
Message Flow:
- CLI → Extension:
emit("webviewMessage", {...}) - Extension → CLI:
emit("extensionWebviewMessage", {...})
- CLI → Extension:
# Run directly from source (no build required)
pnpm dev --provider openrouter --api-key $OPENROUTER_API_KEY --print "Hello"
# Run tests
pnpm test
# Type checking
pnpm check-types
# Linting
pnpm lintBy default the dev script still points ROO_CODE_PROVIDER_URL at http://localhost:8080/proxy for local extension-host development. The CLI provider selection itself should use a non-Router provider such as OpenRouter. To point the backend URL at production instead, override the environment variable:
ROO_CODE_PROVIDER_URL=https://api.roocode.com/proxy pnpm dev --provider openrouter --api-key $OPENROUTER_API_KEY --print "Hello"Official releases are created via the GitHub Actions workflow at .github/workflows/cli-release.yml.
To trigger a release:
- Go to Actions → CLI Release
- Click Run workflow
- Optionally specify a version (defaults to
package.jsonversion) - Click Run workflow
The workflow will:
- Build the CLI on all platforms (macOS Apple Silicon, Linux x64)
- Create platform-specific tarballs with bundled ripgrep
- Verify each tarball
- Create a GitHub release with all tarballs attached
For local development and testing, use the build script:
# Build tarball for your current platform
./apps/cli/scripts/build.sh
# Build and install locally
./apps/cli/scripts/build.sh --install
# Fast build (skip verification)
./apps/cli/scripts/build.sh --skip-verify