Running Claude Code
This guide covers running Claude Code in a Moat container.
Prerequisites
- Moat installed
- Claude Code installed on your host machine with an active subscription (Claude Pro or Max), OR an Anthropic API key
Granting Anthropic credentials
Run moat grant anthropic to configure authentication. You’ll see a menu with available options:
$ moat grant anthropic
Choose authentication method:
1. Claude subscription (recommended)
Uses 'claude setup-token' to get a long-lived OAuth token.
Requires a Claude Pro/Max subscription.
2. Anthropic API key
Use an API key from console.anthropic.com
Billed per token to your API account.
3. Import existing Claude Code credentials
Use OAuth tokens from your local Claude Code installation.
Enter choice [1, 2, or 3]:
Option 1: Claude subscription (recommended)
If you have a Claude Pro or Max subscription and the Claude CLI installed, choose option 1. This runs claude setup-token to obtain a long-lived OAuth token:
Enter choice [1, 2, or 3]: 1
Running 'claude setup-token' to obtain authentication token...
This may open a browser for authentication.
Anthropic credential saved to ~/.moat/credentials/anthropic.enc
You can now run 'moat claude' to start Claude Code.
Option 2: API key
If you have an Anthropic API key (from console.anthropic.com):
Enter choice [1, 2, or 3]: 2
Enter your Anthropic API key.
You can find or create one at: https://console.anthropic.com/settings/keys
API Key: sk-ant-api...
Validate API key with a test request? This makes a small API call. [Y/n]: y
Validating API key...
API key is valid.
Anthropic API key saved to ~/.moat/credentials/anthropic.enc
You can also set ANTHROPIC_API_KEY in your environment before running the command.
Option 3: Import existing credentials
If you already have Claude Code installed and logged in locally, you can import your existing OAuth credentials:
Enter choice [1, 2, or 3]: 3
Found Claude Code credentials.
Subscription: claude_pro
Expires: 2026-02-15T10:30:00Z
Claude Code credentials imported to ~/.moat/credentials/anthropic.enc
Note: Imported tokens do not auto-refresh. When the token expires, run a Claude Code session on your host machine to refresh it, then run moat grant anthropic again to import the new token.
How credentials are injected
The actual credential is never in the container environment. Moat’s proxy intercepts requests to Anthropic’s API and injects the real token at the network layer. See Credential management for details.
Running Claude Code
Interactive mode
Start Claude Code in the current directory:
moat claude
Start in a specific project:
moat claude ./my-project
Claude Code launches in interactive mode with full access to the mounted workspace.
Non-interactive mode
Run with a prompt:
moat claude -p "explain this codebase"
moat claude -p "fix the failing tests"
moat claude -p "add input validation to the user registration form"
Claude Code executes the prompt and exits when complete.
Permission handling
By default, moat claude runs with --dangerously-skip-permissions enabled. This skips Claude Code’s per-tool confirmation prompts that normally ask before each file edit, command execution, or network request.
Security properties:
The container runs as a non-root user with filesystem access limited to the mounted workspace. Credentials are injected at the network layer and never appear in the container environment. See Security model for the full threat model.
Restoring manual approval:
If you prefer Claude Code’s default confirmation behavior, use the --noyolo flag:
moat claude --noyolo ./my-project
With --noyolo, Claude Code prompts for confirmation before each potentially destructive operation, just as it would when running directly on your host machine.
Resuming sessions
When Claude Code exits, Moat captures the session ID from the Claude projects directory on the host filesystem. You can resume a previous session by run name:
moat claude --resume my-feature
This looks up the stored Claude session UUID for the run named my-feature and passes it to Claude Code. You can also pass a raw Claude session UUID directly:
moat claude --resume ae150251-d90a-4f85-a9da-2281e8e0518d
To continue the most recent conversation without specifying a session:
moat claude --continue
Named runs
Give your run a name for reference:
moat claude --name feature-auth ./my-project
The name appears in moat list and makes it easier to manage multiple runs.
Background runs
Run Claude Code in the background:
moat claude -d ./my-project
Reattach later:
$ moat list
NAME RUN ID STATE AGE
feature-auth run_a1b2c3d4e5f6 running 5m
$ moat attach run_a1b2c3d4e5f6
Adding GitHub access
Grant GitHub access so Claude Code can interact with repositories:
moat claude --grant github ./my-project
This injects GitHub credentials alongside Anthropic credentials. Claude Code can:
- Clone repositories
- Push commits
- Create pull requests
- Access private repositories
Configure in agent.yaml for repeated use:
name: my-claude-project
grants:
- anthropic
- github
Then:
moat claude ./my-project
Using an LLM proxy
Route Claude Code API traffic through a host-side proxy for caching, logging, or policy enforcement. Tools like Headroom sit between Claude Code and the Anthropic API.
Install and start Headroom:
pip install "headroom-ai[all]"
headroom proxy --port 8787
Configure claude.base_url in agent.yaml:
grants:
- claude
claude:
base_url: http://localhost:8787
Moat handles the details:
- Sets
ANTHROPIC_BASE_URLinside the container - Routes traffic through a relay on the Moat proxy (
localhostworks because the relay runs on the host) - Injects credentials for both
api.anthropic.comand the proxy host
Start the proxy on your host, then run as usual:
moat claude ./my-project
Adding SSH access
For SSH-based git operations:
moat grant ssh --host github.com
moat claude --grant ssh:github.com ./my-project
Claude Code can use git@github.com:... URLs for cloning and pushing.
Plugin management
Moat supports Claude Code plugins, with automatic discovery of plugins installed on your host machine.
Host plugin inheritance
Plugins you install via Claude Code on your host machine are automatically available in Moat containers:
# Install a plugin on your host
claude plugin marketplace add owner/repo
claude plugin enable plugin-name@repo
The next time you run moat claude, the plugin is available inside the container. Moat reads:
~/.claude/plugins/known_marketplaces.json— Marketplaces registered viaclaude plugin marketplace add~/.claude/settings.json— Plugin enable/disable settings
No additional configuration required. Use --rebuild to update the container image after installing new plugins.
Explicit plugin configuration
For reproducible builds or CI environments, configure plugins explicitly in agent.yaml:
claude:
plugins:
"plugin-name@marketplace": true
Settings in agent.yaml override host settings, giving you control over exactly which plugins are available.
Marketplaces
Configure additional plugin marketplaces:
claude:
marketplaces:
custom:
source: github
repo: owner/repo
ref: main
Marketplaces are cloned during image build. Use --rebuild to update after changing marketplace configuration.
List plugins
View which plugins are configured:
moat claude plugins list ./my-project
This shows plugins from all sources: host settings, project settings, and agent.yaml.
Language servers
Moat includes prepackaged language server configurations that give Claude Code access to code intelligence features like go-to-definition, find-references, and diagnostics. Language servers are installed as Claude Code plugins during image build.
Add language_servers to your agent.yaml:
agent: claude
language_servers:
- go
grants:
- anthropic
Moat installs the language server binary and its runtime dependencies during image build, then enables the corresponding Claude Code plugin. No additional setup is needed.
Available language servers
| Name | Language | Description | Dependencies installed |
|---|---|---|---|
go | Go | Code intelligence, refactoring, diagnostics | go, gopls |
typescript | TypeScript/JavaScript | Code intelligence, diagnostics | node, typescript, typescript-language-server |
python | Python | Code intelligence, type checking, diagnostics | python, pyright |
How it works
When you add a language server to language_servers:
- Moat adds required dependencies to the image build (e.g.,
goandgoplsfor the Go language server) - The corresponding Claude Code plugin is enabled and baked into the container image
- Claude Code discovers and manages the language server through its plugin system
Runtime dependencies are added automatically — listing them in dependencies: is not required. Use --rebuild to update the container image after changing language server configuration.
Multiple language servers
You can enable multiple language servers for polyglot projects:
language_servers:
- go
- typescript
- python
MCP servers
Moat supports both remote and local MCP servers with credential injection. See MCP servers for configuration and usage.
Workspace snapshots
Moat captures workspace snapshots for recovery and rollback. See Snapshots for configuration and usage.
Example: Code review workflow
-
Grant credentials:
moat grant anthropic moat grant github -
Create
agent.yaml:name: code-review grants: - anthropic - github snapshots: triggers: disable_pre_run: false -
Run Claude Code with a review prompt:
moat claude -p "Review the changes in the last 3 commits. Focus on security issues and suggest improvements." -
View what Claude Code did:
moat logs moat trace --network
Troubleshooting
”No Claude Code credentials found”
Claude Code is not installed or not logged in on your host machine. Either:
- Install Claude Code and log in, then run
moat grant anthropicagain - Use an API key:
export ANTHROPIC_API_KEY="sk-ant-..." && moat grant anthropic
”Credential expired”
OAuth credentials have an expiration time. Re-grant:
moat grant anthropic
Claude Code hangs on startup
Check that you’re not running in a directory without an agent.yaml that specifies a conflicting configuration. Try:
moat claude --name test ~/empty-dir
“Failed to install Anthropic marketplace”
Claude Code needs SSH access to GitHub to clone the official Anthropic plugin marketplace. Grant SSH access:
moat grant ssh --host github.com
Then add the grant to your agent.yaml:
grants:
- anthropic
- ssh:github.com
Or pass it on the command line:
moat claude --grant ssh:github.com ./my-project
Network errors
Verify the Anthropic credential is granted:
moat run --grant anthropic -- curl -s https://api.anthropic.com/v1/models
Related guides
- SSH access — Set up SSH for git operations
- Snapshots — Protect your workspace with snapshots
- MCP servers — Extend Claude Code with remote and local MCP servers
- Exposing ports — Access services running inside containers
- Security model — Container isolation and credential injection