| title | CLI reference | |||||
|---|---|---|---|---|---|---|
| navTitle | CLI | |||||
| description | Complete reference for all Moat CLI commands and flags. | |||||
| keywords |
|
Complete reference for Moat CLI commands.
These flags apply to all commands:
| Flag | Description |
|---|---|
-v, --verbose |
Enable verbose output (debug logs) |
--dry-run |
Show what would happen without executing |
--json |
Output in JSON format |
--profile NAME |
Credential profile to use (env: MOAT_PROFILE) |
-h, --help |
Show help for command |
Commands that operate on a run (stop, destroy, logs, trace, audit, snapshot) accept a run ID or a run name:
moat stop run_a1b2c3d4e5f6 # by full ID
moat stop run_a1b2 # by ID prefix
moat stop my-agent # by nameResolution priority: exact ID > ID prefix > exact name.
If a name matches multiple runs, batch commands (stop, destroy) prompt for confirmation while single-target commands (logs) list the matches and ask you to specify a run ID.
The agent commands (moat claude, moat copilot, moat codex, moat gemini, moat pi) share the following flags. These flags work identically across moat claude, moat copilot, moat codex, moat gemini, and moat pi.
| Flag | Description |
|---|---|
-g, --grant PROVIDER |
Inject credential (repeatable). See Grants reference for available providers. |
-e, --env KEY=VALUE |
Set environment variable (repeatable) |
-m, --mount SOURCE:TARGET[:MODE] |
Additional mount (repeatable). See Mounts reference. |
-n, --name NAME |
Run name (default: from moat.yaml or random) |
--rebuild |
Force rebuild of container image |
--allow-host HOST |
Additional hosts to allow network access to (repeatable) |
--runtime RUNTIME |
Container runtime to use (apple, docker) |
--keep |
Keep container after run completes |
--workspace-mode bind|volume |
Workspace mode: bind (default) or volume (isolated Docker named volume). Overrides workspace.mode in moat.yaml. Docker-only for volume. |
--no-clipboard |
Disable host clipboard bridging for this run |
--no-sandbox |
Disable gVisor sandbox (Docker only) |
--no-prompt |
Never prompt to grant missing credentials; fail with the missing-grants error instead. Also set via MOAT_NO_PROMPT=1. Prompting only happens on an interactive terminal. |
--tty-trace FILE |
Capture terminal I/O to file for debugging (e.g., session.json) |
--worktree BRANCH |
Run in a git worktree for this branch (alias: --wt) |
Agent commands run interactively by default, owning the terminal with stdin/stdout/stderr connected. Use -p/--prompt for non-interactive mode (output streams to the terminal). Each agent command also accepts command-specific flags documented in their own sections.
All agent commands support passing an initial prompt after --. Unlike -p, which runs non-interactively and exits when done, arguments after -- start an interactive session with the prompt pre-filled:
moat claude -- "is this thing on?"
moat copilot -- "explain this codebase"
moat codex -- "explain this codebase"Auto-generate a moat.yaml configuration file for an existing project.
moat init [workspace]
Scans the project workspace to detect file types, manifest files, and CI configurations, then runs an AI agent in a bootstrap container to generate an appropriate moat.yaml.
moat init automatically detects which agent credentials are available, in order: Claude, Codex, Gemini. It uses the first agent with valid credentials.
If no credentials are found, the command prints instructions for granting credentials.
| Argument | Description |
|---|---|
workspace |
Project directory to analyze (default: current directory) |
# Generate moat.yaml for the current directory
moat init
# Generate moat.yaml for a specific project
moat init /path/to/projectRun an agent in a container.
moat run [flags] [path] [-- command]
| Argument | Description |
|---|---|
path |
Workspace directory (default: current directory) |
command |
Command to run (overrides moat.yaml) |
| Flag | Description |
|---|---|
-n, --name NAME |
Set run name (used for hostname routing) |
-g, --grant PROVIDER |
Inject credential (repeatable) |
-e, --env KEY=VALUE |
Set environment variable (repeatable) |
-m, --mount SOURCE:TARGET[:MODE] |
Additional mount (repeatable). See Mounts reference. |
-i, --interactive |
Enable interactive mode (stdin + TTY) |
--rebuild |
Force rebuild of container image |
--runtime RUNTIME |
Container runtime to use (apple, docker) |
--keep |
Keep container after run completes |
--no-clipboard |
Disable host clipboard bridging for this run |
--workspace-mode bind|volume |
Workspace mode: bind (default) mounts the host directory at /workspace; volume copies it into an isolated Docker named volume. Overrides workspace.mode in moat.yaml. Docker-only for volume. |
--no-sandbox |
Disable gVisor sandboxing (Docker only) |
--no-prompt |
Never prompt to grant missing credentials; fail with the missing-grants error instead. Also set via MOAT_NO_PROMPT=1. Prompting only happens on an interactive terminal. |
--tty-trace FILE |
Capture terminal I/O to file for debugging (e.g., session.json) |
Non-interactive (default): Output streams to the terminal. Press Ctrl+C to stop.
moat run ./my-projectInteractive (-i): The run owns the terminal with stdin/stdout/stderr connected and a TTY allocated. Ctrl+C is forwarded to the container process. The Ctrl-/ menu offers the following actions:
| Key | Action |
|---|---|
Ctrl-/ s |
Take a manual workspace snapshot |
Ctrl-/ k |
Stop the run |
Ctrl-/ d |
Dump the in-memory TTY history to ~/.moat/runs/<id>/tui-debug-<unix-ts>.json for offline analysis with moat tty-trace analyze |
Ctrl-/ r |
Soft-reset the terminal (recover from rendering corruption) |
Ctrl-/ Ctrl-/ |
Cancel the menu |
The TTY history is captured into a bounded ring buffer (default 8 MB, override with MOAT_TTY_RING_BYTES) for every interactive session, so Ctrl-/ d can be used retroactively after a rendering bug appears.
moat run -i -- bash# Run in current directory
moat run
# Run in specific directory
moat run ./my-project
# Run with credentials
moat run --grant github ./my-project
# Run with custom command
moat run -- npm test
# Run shell command
moat run -- sh -c "npm install && npm test"
# Interactive shell
moat run -i -- bash
# Multiple credentials
moat run --grant github --grant anthropic ./my-project
# Environment variable
moat run -e DEBUG=true ./my-project
# Named run for hostname routing
moat run --name my-feature ./my-project
# Disable gVisor sandbox (when needed for compatibility)
moat run --no-sandbox ./my-projectDisables host clipboard bridging for this run. Overrides clipboard: true in moat.yaml.
moat run --no-clipboard ./my-projectDisables gVisor sandboxing for Docker containers. By default, Moat runs Docker containers with gVisor (runsc) for additional isolation. This flag disables gVisor and uses the standard Docker runtime (runc).
When to use: Some workloads use syscalls that gVisor doesn't support. If your agent fails with syscall-related errors, try --no-sandbox.
Note: This flag only affects Docker containers. Apple containers use macOS virtualization and are unaffected.
moat run --no-sandbox ./my-projectRun Claude Code in a container.
moat claude [workspace] [flags] [-- initial-prompt]
In addition to the command-specific flags below, moat claude accepts all common agent flags.
| Argument | Description |
|---|---|
workspace |
Workspace directory (default: current directory) |
initial-prompt |
Text after -- is passed to Claude as an initial prompt (interactive mode) |
| Flag | Description |
|---|---|
-p, --prompt TEXT |
Run non-interactive with prompt |
-c, --continue |
Continue the most recent conversation |
-r, --resume RUN|UUID |
Resume a specific session by moat run name/ID or raw Claude session UUID |
--noyolo |
Restore Claude Code's per-operation confirmation prompts. By default, moat claude runs with --dangerously-skip-permissions because the container provides isolation. Use --noyolo to re-enable permission prompts. |
# Interactive Claude Code
moat claude
# In specific directory
moat claude ./my-project
# Interactive with initial prompt (Claude stays open)
moat claude -- "is this thing on?"
moat claude ./my-project -- "explain this codebase"
# Non-interactive with prompt (exits when done)
moat claude -p "fix the failing tests"
# Continue the most recent conversation
moat claude --continue
moat claude -c
# Resume a specific session by run name
moat claude --resume my-feature
# Resume by raw Claude session UUID
moat claude --resume ae150251-d90a-4f85-a9da-2281e8e0518d
# With GitHub access
moat claude --grant github
# Named run
moat claude --name feature-auth ./my-project
# Run in a git worktree (non-interactive with prompt)
moat claude --worktree=dark-mode --prompt "implement dark mode"
# Require manual approval for each tool use
moat claude --noyoloRun GitHub Copilot CLI in a container.
moat copilot [workspace] [flags] [-- initial-prompt]
In addition to the command-specific flags below, moat copilot accepts all common agent flags.
moat copilot uses the github grant. Before creating the run, Moat checks that the stored GitHub credential can use Copilot. The container receives only Copilot/GitHub token placeholders; Moat's proxy injects the real GitHub token for GitHub API, Copilot API, and HTTPS git requests.
| Argument | Description |
|---|---|
workspace |
Workspace directory (default: current directory) |
initial-prompt |
Text after -- is passed to Copilot as an initial prompt (interactive mode) |
| Flag | Description |
|---|---|
-p, --prompt TEXT |
Run non-interactive with prompt |
--allow-all |
Allow all Copilot tools, paths, and URLs without prompting. Default: true. |
--model MODEL |
Select the model to use. Overrides copilot.model. |
--experimental |
Enable Copilot CLI experimental features. |
--autopilot |
Start Copilot CLI in autopilot mode. |
# One-time credential setup
moat grant github
# Interactive Copilot CLI
moat copilot
# In specific directory
moat copilot ./my-project
# Interactive with initial prompt
moat copilot -- "explain this codebase"
# Non-interactive with prompt
moat copilot -p "fix the failing tests"
# Select a model
moat copilot --model gpt-5.4
# Run in a git worktree
moat copilot --worktree=dark-mode --prompt "implement dark mode"Run OpenAI Codex CLI in a container.
moat codex [workspace] [flags] [-- initial-prompt]
In addition to the command-specific flags below, moat codex accepts all common agent flags.
| Argument | Description |
|---|---|
workspace |
Workspace directory (default: current directory) |
initial-prompt |
Text after -- is passed to Codex as an initial prompt (interactive mode) |
| Flag | Description |
|---|---|
-p, --prompt TEXT |
Run non-interactive with prompt |
--full-auto |
Enable full-auto mode (auto-approve tool use). Default: true. Set --full-auto=false to require manual approval for each action. This is analogous to --noyolo on moat claude -- the container provides isolation, so auto-approval is the default. |
# Interactive Codex CLI
moat codex
# In specific directory
moat codex ./my-project
# Interactive with initial prompt (Codex stays open)
moat codex -- "testing"
moat codex ./my-project -- "explain this codebase"
# Non-interactive with prompt (exits when done)
moat codex -p "explain this codebase"
moat codex -p "fix the bug in main.py"
# With GitHub access
moat codex --grant github
# Named run
moat codex --name my-feature
# Run in a git worktree (non-interactive with prompt)
moat codex --worktree=dark-mode --prompt "implement dark mode"
# Force rebuild
moat codex --rebuild
# Disable full-auto mode (require manual approval)
moat codex --full-auto=falseRun Google Gemini CLI in a container.
moat gemini [workspace] [flags]
In addition to the command-specific flags below, moat gemini accepts all common agent flags.
| Argument | Description |
|---|---|
workspace |
Workspace directory (default: current directory) |
| Flag | Description |
|---|---|
-p, --prompt TEXT |
Run non-interactive with prompt |
Gemini does not have a --noyolo or --full-auto equivalent. The Gemini CLI does not expose a flag to skip confirmation prompts.
# Interactive Gemini CLI
moat gemini
# In specific directory
moat gemini ./my-project
# Non-interactive with prompt
moat gemini -p "explain this codebase"
moat gemini -p "fix the bug in main.py"
# With GitHub access
moat gemini --grant github
# Named run
moat gemini --name my-feature
# Run in a git worktree (non-interactive with prompt)
moat gemini --worktree=dark-mode --prompt "implement dark mode"
# Force rebuild
moat gemini --rebuildRun the Pi coding agent in a container.
moat pi [workspace] [flags] [-- initial-prompt]
In addition to the command-specific flags below, moat pi accepts all common agent flags.
Pi has no credential of its own — it runs against your anthropic or openai grant. When exactly one of those grants is configured it is used automatically; when both are configured you must choose one with --provider (or pi.provider in moat.yaml). Only the anthropic and openai backends are supported today; any other value fails hard. If no supported grant is configured, moat pi exits before creating a container and tells you to run moat grant anthropic or moat grant openai.
| Argument | Description |
|---|---|
workspace |
Workspace directory (default: current directory) |
initial-prompt |
Text after -- is passed to Pi as an initial prompt (interactive mode) |
| Flag | Description |
|---|---|
-p, --prompt TEXT |
Run non-interactive with prompt |
--provider NAME |
Model backend: anthropic or openai. Overrides pi.provider; required when both grants are configured. |
--model PATTERN |
Model pattern to use (overrides pi.model). When unset, Pi's per-provider default is used. |
# Grant a backend, then run Pi (backend inferred from the single grant)
moat grant anthropic
moat pi
# In a specific directory
moat pi ./my-project
# Non-interactive with prompt
moat pi -p "explain this codebase"
# Force the OpenAI backend (e.g. when both grants are configured)
moat pi --provider openai
# Pin a model
moat pi --provider anthropic --model claude-opus-4-8
# With GitHub access
moat pi --grant github
# Run in a git worktree (non-interactive with prompt)
moat pi --worktree=dark-mode --prompt "implement dark mode"
# Force rebuild
moat pi --rebuildCreate or reuse a git worktree for a branch and start a run in it.
moat wt <branch> [-- command]
The branch is created from HEAD if it doesn't exist. The worktree is created at ~/.moat/worktrees/<repo-id>/<branch>.
Configuration is read from moat.yaml in the repository root. If a run is already active in the worktree, returns an error with instructions to stop it.
| Argument | Description |
|---|---|
branch |
Branch name to create or reuse a worktree for |
command |
Command to run (overrides moat.yaml) |
| Flag | Description |
|---|---|
-n, --name NAME |
Override auto-generated run name |
-g, --grant PROVIDER |
Inject credential (repeatable) |
-e KEY=VALUE |
Set environment variable (repeatable) |
--rebuild |
Force image rebuild |
--keep |
Keep container after completion |
--runtime |
Container runtime to use (apple, docker) |
--no-clipboard |
Disable host clipboard bridging for this run |
--no-sandbox |
Disable gVisor sandbox (Docker only) |
--no-prompt |
Never prompt to grant missing credentials; fail instead. Also set via MOAT_NO_PROMPT=1. |
--tty-trace FILE |
Capture terminal I/O to file for debugging |
The run name is {name}-{branch} when moat.yaml has a name field, otherwise just {branch}.
Override the default worktree base path (~/.moat/worktrees/) with the MOAT_WORKTREE_BASE environment variable.
# Start a run in a worktree for the dark-mode branch
moat wt dark-mode
# Run a specific command in the worktree
moat wt dark-mode -- make test
# List worktree-based runs
moat wt list
# Clean all stopped worktrees
moat wt clean
# Clean a specific worktree
moat wt clean dark-modeList worktree-based runs for the current repository. Equivalent to moat list filtered to worktree runs in the current repo.
moat wt listRemove worktree directories for stopped runs. Without arguments, cleans all stopped worktrees for the current repository. Never deletes branches.
moat clean also removes worktree directories as part of its broader cleanup. Use moat wt clean to target a specific branch or limit cleanup to worktrees.
moat wt clean [branch]Examples:
# Clean all stopped worktrees for the current repo
moat wt clean
# Clean a specific worktree
moat wt clean dark-modeStore credentials for injection into runs. See Grants reference for details on each provider, host matching rules, and credential sources.
moat grant <provider>[:<scopes>]
| Provider | Description |
|---|---|
github |
GitHub (gh CLI, env var, or PAT) |
claude |
Claude Code OAuth token |
anthropic |
Anthropic API key |
openai |
OpenAI (API key) |
gemini |
Google Gemini (Gemini CLI OAuth or API key) |
npm |
npm registries (.npmrc, NPM_TOKEN, or manual) |
aws |
AWS (IAM role assumption) |
oauth |
OAuth 2.0 (authorization code flow with PKCE) |
GitHub credentials are obtained from multiple sources, in order of preference:
- Environment variable -- Uses
GITHUB_TOKENorGH_TOKENif set - gh CLI -- Uses token from
gh auth tokenif available - Personal Access Token -- Interactive prompt for manual entry
moat grant githubStores a Claude Code OAuth token. Presents a menu of OAuth token sources (setup-token, paste existing, or import from local Claude Code).
OAuth tokens are stored as claude.enc. See Grants reference for details.
moat grant claudeStores an Anthropic API key. Reads from ANTHROPIC_API_KEY environment variable, or prompts interactively.
API keys are stored as anthropic.enc. Both credentials can coexist with claude.
moat grant anthropicStores an OpenAI API key. Reads from the OPENAI_API_KEY environment variable, or prompts interactively.
moat grant openaiStores a Google Gemini credential. Supports two authentication methods:
- Gemini CLI OAuth (recommended) -- Imports OAuth tokens from your local Gemini CLI installation (
gemini). Refresh tokens are stored for automatic access token renewal. If Gemini CLI credentials are detected, you are prompted to choose between OAuth import and API key. - API key -- Uses an API key from
aistudio.google.com/apikey. Reads fromGEMINI_API_KEYenvironment variable, or prompts interactively.
If no Gemini CLI credentials are found, falls directly to the API key prompt.
# Import from Gemini CLI or enter API key
moat grant geminiGrant npm registry credentials. Auto-discovers registries from ~/.npmrc and NPM_TOKEN environment variable.
moat grant npm [flags]
| Flag | Description |
|---|---|
--host HOSTNAME |
Specific registry host (e.g., npm.company.com) |
# Auto-discover registries from .npmrc
moat grant npm
# Add a specific registry
moat grant npm --host=npm.company.comStore a credential for an MCP server.
moat grant mcp context7The credential is stored as mcp:<name> (e.g., mcp:context7), mirroring the oauth:<name> convention, and can be referenced in moat.yaml. The deprecated mcp-<name> (hyphen) form is still accepted for existing grants.
Interactive prompts:
- Credential (hidden input)
Storage:
~/.moat/credentials/mcp:<name>.enc
Grant OAuth credentials for a service. Acquires tokens via a browser-based authorization code flow with PKCE.
moat grant oauth <name> [flags]
| Flag | Description |
|---|---|
--url |
MCP server URL for OAuth discovery |
--auth-url |
OAuth authorization endpoint |
--token-url |
OAuth token endpoint |
--client-id |
OAuth client ID |
--client-secret |
OAuth client secret |
--scopes |
OAuth scopes (space-separated) |
Config resolution order: CLI flags, then ~/.moat/oauth/<name>.yaml, then MCP discovery from --url.
# Auto-discover OAuth endpoints from an MCP server
moat grant oauth notion --url https://mcp.notion.com/mcp
# Provide endpoints directly
moat grant oauth linear \
--auth-url https://linear.app/oauth/authorize \
--token-url https://linear.app/api/oauth/token \
--client-id your-client-id \
--scopes "read write"After a successful grant for a well-known server, the command prints a ready-to-paste shorthand:
mcp:
- linearStorage:
~/.moat/credentials/oauth-<name>.enc
Grant SSH access to a specific host.
moat grant ssh --host <hostname>
| Flag | Description |
|---|---|
--host HOSTNAME |
Host to grant access to (required) |
moat grant ssh --host github.com
moat grant ssh --host gitlab.comGrant AWS credentials via IAM role assumption.
moat grant aws --role=<ARN> [flags]
| Flag | Description | Default |
|---|---|---|
--role ARN |
IAM role ARN to assume (required) | -- |
--region REGION |
AWS region for API calls | us-east-1 |
--session-duration DURATION |
Session duration (e.g., 1h, 30m, 15m) |
15m |
--external-id ID |
External ID for cross-account role assumption | -- |
--aws-profile PROFILE |
AWS shared config profile for role assumption (falls back to AWS_PROFILE env var) |
-- |
# Basic role assumption
moat grant aws --role arn:aws:iam::123456789012:role/AgentRole
# With explicit region
moat grant aws --role arn:aws:iam::123456789012:role/AgentRole --region us-west-2
# With custom session duration
moat grant aws --role arn:aws:iam::123456789012:role/AgentRole --session-duration 2h
# Cross-account with external ID
moat grant aws --role arn:aws:iam::987654321098:role/CrossAccountRole --external-id abc123
# Full example
moat grant aws \
--role arn:aws:iam::123456789012:role/AgentRole \
--region eu-west-1 \
--session-duration 30mList stored credentials. Shows credentials from the active profile, or the default store if no profile is set.
moat grant list
moat grant list
moat grant list --json
moat grant list --profile workShow details of a stored credential. Displays the provider, type, source, scopes, expiration, and a redacted token.
moat grant show <provider>
For SSH credentials, use ssh:<host> format.
| Flag | Description |
|---|---|
--show-token |
Reveal the full credential value (redacted by default) |
moat grant show github # Show GitHub credential details
moat grant show github --show-token # Reveal the full token
moat grant show aws # Show AWS role configuration
moat grant show ssh:github.com # Show SSH key details
moat grant show github --json # Output as JSON
moat grant show github --profile myproj # Show profile credential| Field | Description |
|---|---|
| Provider | Provider name |
| Type | Credential type (token, oauth, api-key, role, key) |
| Source | How the credential was obtained (cli, env, pat, oauth) |
| Scopes | OAuth scopes, if applicable |
| Granted | When the credential was stored |
| Expires | Expiration time, or "never" |
| Token | Last 4 characters shown by default; full value with --show-token |
Provider-specific fields (AWS role ARN, region, session duration; SSH fingerprint and key path; npm registries) are shown when applicable.
List all available credential providers.
moat grant providers # List all providers
moat grant providers --json # Output as JSONOutput columns:
| Column | Description |
|---|---|
| PROVIDER | Provider name (used with moat grant <name>) |
| DESCRIPTION | Brief description |
| TYPE | builtin or custom |
Remove stored credentials. Operates on the active profile, or the default store if no profile is set.
moat revoke <provider>
moat revoke github
moat revoke claude # revokes OAuth token
moat revoke anthropic # revokes API key
moat revoke npm
moat revoke ssh:github.com
# Revoke from a specific profile
moat revoke github --profile workView container logs.
moat logs [flags] [run]
| Argument | Description |
|---|---|
run |
Run ID or name (default: most recent) |
| Flag | Description |
|---|---|
-n, --lines N |
Show last N lines (default: 100) |
-f, --follow |
Stream new log lines as they are written (exit with Ctrl+C) |
# Most recent run
moat logs
# By name
moat logs my-agent
# By ID
moat logs run_a1b2c3d4e5f6
# Last 50 lines
moat logs -n 50
# Follow logs from a running container
moat logs -f my-agent
# Show last 20 lines, then follow
moat logs -n 20 -f my-agentView execution traces and network requests.
moat trace [flags] [run]
| Argument | Description |
|---|---|
run |
Run ID or name (default: most recent) |
| Flag | Description |
|---|---|
--network |
Show network requests instead of spans |
-v, --verbose |
Show headers and bodies (requires --network) |
# Execution spans
moat trace
# Network requests
moat trace --network
# Network with details
moat trace --network -v
# By name or ID
moat trace --network my-agent
moat trace --network run_a1b2c3d4e5f6Verify audit log integrity.
moat audit [flags] <run>
| Argument | Description |
|---|---|
run |
Run ID or name |
| Flag | Description |
|---|---|
-e, --export FILE |
Export proof bundle |
# Verify by name or ID
moat audit my-agent
moat audit run_a1b2c3d4e5f6
# Export proof bundle
moat audit run_a1b2c3d4e5f6 --export proof.jsonVerify an exported proof bundle.
moat audit verify <file>
moat audit verify proof.jsonList all runs.
moat list
| Column | Description |
|---|---|
| NAME | Run name |
| RUN ID | Unique identifier |
| RUNTIME | Container runtime (docker, apple) |
| STATE | running, stopped, failed |
| AGE | Time since run was created |
| WORKTREE | Branch name (appears when any run has a worktree) |
| ENDPOINTS | Exposed services (from ports) |
The WORKTREE column appears when any run has a worktree branch. To show only worktree runs for the current repository, use moat wt list.
Open a running agent's endpoint in your browser.
moat open [agent] [endpoint] [flags]
With no arguments, opens the discovery index listing every running agent and its endpoints. With an agent name, opens that agent's page; add an endpoint name to open a specific endpoint directly.
When no agent is given, moat uses the agent named in the current directory's moat.yaml, or the only running agent if there's exactly one.
The resolved URL is always printed, so it still works on a headless or SSH session where no browser is available.
| Argument | Description |
|---|---|
agent |
Agent name. Optional — defaults from the current directory's moat.yaml, or the sole running agent. |
endpoint |
Endpoint name from ports:. Optional. |
| Flag | Description |
|---|---|
-p, --print |
Print the URL without opening a browser |
# Index of every running agent and endpoint
moat open
# The "my-app" agent (its endpoint index, or its sole endpoint)
moat open my-app
# my-app's "web" endpoint
moat open my-app web
# Print the URL without launching a browser
moat open --print my-appShow high-level system status summary.
moat status
- Runtime: Available container runtimes (shows all available, e.g., "docker, apple")
- Active Runs: Currently running containers with age, disk usage, and endpoints
- Summary: Counts and disk usage for stopped runs and cached images
- Health: Warnings about stopped runs and orphaned containers
| Column | Description |
|---|---|
| NAME | Run name |
| RUN ID | Unique run identifier |
| RUNTIME | Container runtime (docker or apple) |
| AGE | Time since run was created |
| DISK | Disk usage in MB |
| ENDPOINTS | Exposed services (from ports) |
With --json, emits a single object:
| Field | Type | Description |
|---|---|---|
| runtimes | string[] | Available container runtimes |
| active_runs | object[] | Currently active runs |
| active_runs[].name | string | Run name |
| active_runs[].id | string | Run ID |
| active_runs[].runtime | string | Container runtime (empty for legacy runs) |
| active_runs[].state | string | Run state |
| active_runs[].age | string | Human-readable age |
| active_runs[].disk_mb | integer | Disk usage in MB (-1 if unknown) |
| active_runs[].endpoints | string | Comma-separated endpoint names (omitted when empty) |
| images | object[] | Cached container images |
| images[].tag | string | Image tag |
| images[].runtime | string | Container runtime |
| images[].size | integer | Image size in bytes |
| images[].created | string | RFC 3339 timestamp |
| health | object[] | Health warnings |
| health[].status | string | "ok" or "warning" |
| health[].message | string | Description |
| total_disk_bytes | integer | Total disk usage in bytes |
For detailed information about all runs, use moat list.
For image details, use moat system images
Stop a running container.
moat stop [run]
| Argument | Description |
|---|---|
run |
Run ID or name (default: most recent running) |
If a name matches multiple runs, you'll be prompted to confirm stopping all of them.
# Stop most recent
moat stop
# Stop by name
moat stop my-agent
# Stop by ID
moat stop run_a1b2c3d4e5f6Run a command inside a running container.
moat exec <run> -- <command> [args...]
| Argument | Description |
|---|---|
run |
Run ID or name |
command |
Command and arguments to execute (after --) |
The exit code from the executed command is forwarded to the caller. If stdin is piped, it is forwarded to the command.
# Run a command
moat exec run_a1b2c3d4e5f6 -- echo hello
# List workspace files
moat exec run_a1b2c3d4e5f6 -- ls /workspace
# Pipe data to a command
echo "data" | moat exec run_a1b2c3d4e5f6 -- cat
# Run a shell command
moat exec run_a1b2c3d4e5f6 -- sh -c "ps aux"Launch a second agent inside a running container, reusing its workspace, grants, and credentials.
moat join <run> <agent> [flags]
moat join is the run-first counterpart to moat exec: where exec runs an arbitrary command, join resolves an agent provider by name, constructs its standard in-container invocation, and execs it into the existing container. The original run owns the container lifecycle — stopping the run tears down the container and any joined agents.
v1 supports same-agent joins only (e.g. joining claude into a run started by moat claude). The agent argument must match the agent the run was created with.
| Argument | Description |
|---|---|
run |
Run ID or name of the target (must be in the running state) |
agent |
Agent to launch (claude) |
| Flag | Description |
|---|---|
-c, --continue |
Continue the most recent conversation |
-r, --resume ID |
Resume a specific session by ID |
-p, --prompt TEXT |
Run with a prompt (non-interactive; exits when done) |
--continue and --resume are mutually exclusive.
Without --prompt, the join session is interactive: stdin, stdout, and stderr are connected to the terminal, and the status footer shows joined · N to indicate the session role and index.
# Interactive join — second claude session in the same workspace
moat join run_a1b2c3d4e5f6 claude
# Join and continue the most recent conversation
moat join run_a1b2c3d4e5f6 claude --continue
# Headless join — run a prompt and exit
moat join run_a1b2c3d4e5f6 claude -p "summarize the diff"
# Identify the run by name
moat join my-feature claudeRemove a stopped run and its artifacts.
moat destroy [run] [flags]
| Argument | Description |
|---|---|
run |
Run ID or name (default: most recent stopped) |
| Flag | Description |
|---|---|
-f, --force |
Destroy even if a volume-mode run has no extraction snapshot |
If a name matches multiple runs, you'll be prompted to confirm destroying all of them.
For volume-mode runs, the workspace lives only in the Docker named volume. Destroying such a run without first capturing a snapshot permanently deletes the agent's work. The command refuses unless an extraction snapshot exists; pass -f/--force to override.
# Destroy by name
moat destroy my-agent
# Destroy by ID
moat destroy run_a1b2c3d4e5f6
# Destroy a volume-mode run even without an extraction snapshot
moat destroy --force run_a1b2c3d4e5f6Clean up stopped runs, unused images, and worktree directories.
moat clean [flags]
Removes stopped runs, unused moat images, orphaned networks, and worktree directories for stopped runs. Worktree cleanup requires running from inside a git repository.
| Flag | Description |
|---|---|
-f, --force |
Skip the confirmation prompt. Does not remove volume-mode runs that lack an extraction snapshot — those are skipped to protect un-extracted work. |
--force-volumes |
Also remove volume-mode runs that have no extraction snapshot. This deletes the workspace volume and loses all agent changes. |
--dry-run |
Show what would be removed |
Volume-mode runs hold the agent's only copy of its work in a Docker named volume. moat clean skips such runs unless they have an extraction snapshot, even with --force, and exits non-zero when it skips any (so scripts can detect it). Snapshot them first (moat snapshot <run>), or pass --force-volumes to discard them.
# Interactive cleanup
moat clean
# Skip the confirmation prompt (still protects un-extracted volume runs)
moat clean -f
# Also remove un-extracted volume runs (destroys their workspace volumes)
moat clean --force-volumes
# Preview cleanup
moat clean --dry-runTo clean a single branch's worktree, use moat wt clean <branch>.
Manage persistent volumes.
These commands manage type: bind volumes (the default): host directories at ~/.moat/volumes/<agent-name>/<volume-name>/ that persist across runs for the same agent name, created automatically when moat.yaml specifies a volumes: section.
A type: volume entry is a native Docker named volume (moat_<agent-name>_<volume-name>) and is not managed by these commands — list it with docker volume ls and remove it with docker volume rm. See moat.yaml › Volumes for the difference.
List managed volumes.
moat volumes ls
Remove all volumes for an agent.
moat volumes rm <agent-name> [flags]
| Flag | Description |
|---|---|
-f, --force |
Skip confirmation prompt |
moat volumes rm my-agent
moat volumes rm my-agent --forceRemove all managed volumes.
moat volumes prune [flags]
| Flag | Description |
|---|---|
-f, --force |
Skip confirmation prompt |
moat volumes prune
moat volumes prune --forceCreate and manage workspace snapshots.
When called with a run argument, creates a manual snapshot. Use subcommands to list, prune, or restore snapshots. All snapshot commands accept a run ID or name.
moat snapshot <run> [flags]
| Flag | Description |
|---|---|
--label TEXT |
Optional label for the snapshot |
For volume-mode runs (workspace.mode: volume), moat snapshot captures /workspace from the Docker named volume rather than from the host directory. The snapshot includes .git (so commits the agent made inside the container are preserved). This is the primary way to extract changes from a volume-mode run.
moat snapshot my-agent
moat snapshot run_a1b2c3d4e5f6
moat snapshot run_a1b2c3d4e5f6 --label "before refactor"List snapshots for a run.
moat snapshot list <run>
moat snapshot list my-agent
moat snapshot list run_a1b2c3d4e5f6 --jsonRemove old snapshots, keeping the newest N. The pre-run snapshot is always preserved.
moat snapshot prune <run> [flags]
| Flag | Description |
|---|---|
--keep N |
Keep N most recent (default: 5) |
--dry-run |
Preview what would be deleted |
moat snapshot prune my-agent --keep 3
moat snapshot prune run_a1b2c3d4e5f6 --dry-runRestore workspace from a snapshot. If no snapshot ID is given, restores the most recent. A safety snapshot is created before in-place restores.
moat snapshot restore <run> [snapshot-id] [flags]
| Flag | Description |
|---|---|
--to DIR |
Extract to a different directory instead of restoring in-place |
In-place restore is blocked for volume-mode runs. The purpose of volume mode is to prevent writes back to the host, so restoring directly would defeat it. Use --to to extract the snapshot to a directory outside the run:
moat snapshot restore run_a1b2c3d4e5f6 --to ~/outputThen fetch the agent's commits into your repository:
git -C ~/myrepo fetch ~/outputmoat snapshot restore my-agent
moat snapshot restore run_a1b2c3d4e5f6 snap_abc123
moat snapshot restore run_a1b2c3d4e5f6 --to /tmp/recoveryManage the proxy daemon. The proxy daemon is a long-lived process that handles credential injection, MCP relay, and hostname routing for all runs. It starts automatically when you run moat run and shuts down after 5 minutes idle (no active runs).
When called without a subcommand, shows the current proxy status.
Start the proxy daemon in the foreground. The daemon serves both the credential-injecting proxy and the routing reverse proxy on a single port.
This is primarily useful for debugging. In normal use, the daemon auto-starts on moat run.
moat proxy start [flags]
| Flag | Description |
|---|---|
-p, --port N |
Proxy listen port (default: 8080) |
moat proxy start
moat proxy start --port 9000Send a shutdown request to the proxy daemon via its Unix socket (~/.moat/proxy/daemon.sock). The daemon drains active connections before exiting.
moat proxy stop
Show daemon status: PID, proxy port, uptime, active run count, and registered routes.
moat proxy status
Stop the running proxy daemon and start a fresh one from the current binary. Use this to adopt a newer moat binary without waiting for the idle timeout.
The restart holds the daemon spawn lock across the entire stop and start sequence. Health monitors from active runs block on that lock until the new daemon is healthy, so an active run cannot resurrect the old daemon in the gap. The proxy port is preserved so existing containers keep working.
moat proxy restart
Manage dependencies. See Dependencies for details on the dependency system.
List available dependencies from the registry.
moat deps list [flags]
| Flag | Description |
|---|---|
--type TYPE |
Filter by dependency type (runtime, npm, apt, github-binary, go-install, uv-tool, custom, meta) |
Show detailed information about a dependency.
moat deps info <name>
# List all dependencies
moat deps list
# List only runtimes
moat deps list --type runtime
# List npm packages
moat deps list --type npm
# Show details for node
moat deps info node
# Show details for a meta dependency
moat deps info go-extrasLow-level system commands.
List moat-managed container images across all available runtimes.
moat system images
| Column | Description |
|---|---|
| IMAGE ID | Short image identifier |
| TAG | Image tag |
| RUNTIME | Container runtime (docker, apple) |
| SIZE | Image size in MB |
| CREATED | Time since image was created |
With --json, emits an array of objects:
| Field | Type | Description |
|---|---|---|
| id | string | Full image ID |
| tag | string | Image tag |
| size | integer | Image size in bytes |
| created | string | RFC 3339 timestamp |
| runtime | string | Container runtime (docker, apple) |
List moat containers across all available runtimes.
moat system containers
| Column | Description |
|---|---|
| CONTAINER ID | Container identifier |
| NAME | Container name |
| RUNTIME | Container runtime (docker, apple) |
| STATUS | Container status (running, exited, etc.) |
| CREATED | Time since container was created |
With --json, emits an array of objects:
| Field | Type | Description |
|---|---|---|
| id | string | Container ID |
| name | string | Container name |
| image | string | Image name |
| status | string | Container status (running, exited, created) |
| created | string | RFC 3339 timestamp |
| runtime | string | Container runtime (docker, apple) |
Clean up orphaned temporary directories.
moat system clean-temp [flags]
Moat creates temporary directories in /tmp for AWS credentials, Claude configuration, and Codex configuration. These are normally cleaned up when a run completes, but may accumulate if moat crashes.
This command scans for and removes temporary directories matching these patterns:
moat-aws-*- AWS credential helper directoriesagentops-aws-*- AWS credential helper directories (legacy)moat-claude-staging-*- Claude configuration staging directoriesmoat-codex-staging-*- Codex configuration staging directoriesmoat-npm-*- npm credential configuration directories
Only directories older than --min-age are removed.
| Flag | Description |
|---|---|
--min-age DURATION |
Minimum age of temp directories to clean (default: 1h) |
--dry-run |
Show what would be cleaned without removing anything |
-f, --force |
Skip confirmation prompt |
# Show orphaned temp directories (dry run)
moat system clean-temp --dry-run
# Clean directories older than 24 hours
moat system clean-temp --min-age=24h
# Clean with automatic confirmation
moat system clean-temp --force
# Clean directories older than 1 week
moat system clean-temp --min-age=168hDiagnostic information about the Moat environment.
moat doctor [flags]
Shows version, container runtime status, credential status, Claude Code configuration, and recent runs. All sensitive information is automatically redacted.
| Flag | Description |
|---|---|
-v, --verbose |
Show verbose output including JWT claims |
moat doctor
moat doctor --verboseDiagnose Claude Code authentication and configuration issues in moat containers.
moat doctor claude [flags]
Compares your host Claude Code configuration against what's available in moat containers to identify authentication problems. Checks host ~/.claude.json fields, credential status (OAuth vs API key, expiration), and field mapping via the host config allowlist.
With --test-container, runs three progressive validation levels that short-circuit on failure:
- Direct API call -- verifies the stored token is valid by calling the Anthropic API from the host
- Proxy injection -- spins up a TLS-intercepting proxy and verifies it replaces placeholder credentials with real ones
- Container test -- launches a real moat container for full end-to-end verification
If level 1 fails (bad token), levels 2 and 3 are skipped. If level 2 fails (proxy issue), level 3 is skipped. This tells you exactly which layer is broken.
Flags:
| Flag | Description |
|---|---|
--verbose |
Show full configuration diff and all checked fields |
--json |
Output results as JSON for scripting |
--test-container |
Run progressive token validation and container auth test (~$0.0001 per level) |
Exit codes:
| Code | Meaning |
|---|---|
| 0 | All checks passed |
| 1 | Configuration issues detected |
| 2 | Token validation or container authentication test failed (--test-container only) |
Examples:
# Basic diagnostics
moat doctor claude
# Full field-level diff
moat doctor claude --verbose
# JSON output for scripting
moat doctor claude --json
# End-to-end container auth test
moat doctor claude --test-container
# Combine flags
moat doctor claude --test-container --verbosePrint the version of moat.
moat version
Capture and analyze terminal I/O for debugging TUI rendering issues.
Use the --tty-trace flag with moat claude, moat run -i, or moat wt to capture traces, then analyze them with moat tty-trace analyze.
Analyze a terminal I/O trace file.
moat tty-trace analyze <trace-file> [flags]
| Flag | Description |
|---|---|
--decode |
Decode and display all control sequences |
--find-clears |
Find screen clear operations |
--find-resize-issues |
Find potential resize timing issues |
--resize-window N |
Time window in ms for resize issue detection (default: 100) |
# Capture a trace during a Claude session
moat claude --tty-trace=session.json
# Decode all control sequences
moat tty-trace analyze session.json --decode
# Find resize timing issues
moat tty-trace analyze session.json --find-resize-issues