Run Claude Code in a Container
This page describes action: harness.run with provider: claude inside a Docker or Podman container.
The examples use an image named dagu-claude-runner:local. Build that image before running the DAG examples.
Requirements
- The Dagu process can reach Docker or Podman.
- The runner image contains
claudeinPATH. - The container can reach the network for real
claude -pruns. - Authentication is provided with
ANTHROPIC_API_KEY,ANTHROPIC_AUTH_TOKEN,CLAUDE_CODE_OAUTH_TOKEN, cloud-provider environment variables, or a mounted Claude Code credentials directory.
Claude Code's current installation and authentication behavior is documented by Anthropic:
Build the Runner Image
Claude Code can be installed as a global npm package. The package requires Node.js 18 or later.
FROM node:22-bookworm-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
git \
ripgrep \
bash \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g @anthropic-ai/claude-code
RUN claude --version
WORKDIR /workspace
ENTRYPOINT []
CMD ["bash"]Build and verify the image:
docker build -t dagu-claude-runner:local -f Dockerfile .
docker run --rm dagu-claude-runner:local claude --versionVerify the Image Through Dagu
This DAG starts a container and calls claude --version. It does not make a model request.
type: graph
harnesses:
shell:
binary: sh
prefix_args:
- -c
prompt_mode: arg
steps:
- id: claude_version
action: harness.run
container:
image: dagu-claude-runner:local
pull_policy: never
with:
provider: shell
prompt: |
set -eu
claude --version
command -v claudeThe command must print the Claude Code version and the path to the claude binary.
Step-Level Container
Use a step-level container when only the Claude Code step should receive the workspace mount and credential.
steps:
- id: review
action: harness.run
container:
image: dagu-claude-runner:local
pull_policy: never
working_dir: /workspace
volumes:
- .:/workspace:ro
env:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
with:
provider: claude
prompt: |
Review this repository and summarize the highest-risk issues.
model: sonnetprovider: claude invokes claude -p "<prompt>". In non-interactive mode, Claude Code uses ANTHROPIC_API_KEY when that variable is present.
Root-Level Container
Use root-level container: when ordinary command steps and Claude Code should share the same container filesystem and toolchain.
type: graph
container:
image: dagu-claude-runner:local
pull_policy: never
working_dir: /workspace
volumes:
- .:/workspace
harnesses:
shell:
binary: sh
prefix_args:
- -c
prompt_mode: arg
steps:
- id: test
run: npm test
- id: claude_tools
action: harness.run
with:
provider: shell
prompt: |
set -eu
claude --version
command -v claudeThis example verifies the shared container path without making a model request. For a real Claude Code step, replace the shell provider with provider: claude and pass authentication.
If the root-level container receives an Anthropic key, bearer token, OAuth token, or mounted Claude credentials, every inherited step in that shared container can read it.
Authentication
Claude Code chooses credentials in the order documented by Anthropic. For Dagu container runs, the credential must be available inside the container.
API Key
env:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}Bearer Token
env:
- ANTHROPIC_AUTH_TOKEN=${ANTHROPIC_AUTH_TOKEN}Long-Lived OAuth Token
Generate the token on the host:
claude setup-tokenThen pass it to the container:
env:
- CLAUDE_CODE_OAUTH_TOKEN=${CLAUDE_CODE_OAUTH_TOKEN}Anthropic documents that --bare does not read CLAUDE_CODE_OAUTH_TOKEN. Do not set bare: true in the Dagu step when this token is the only credential.
Mounted Credentials Directory
On Linux, Claude Code stores credentials under ~/.claude/.credentials.json unless CLAUDE_CONFIG_DIR is set. Mount the host directory and set CLAUDE_CONFIG_DIR inside the container:
steps:
- id: review
action: harness.run
container:
image: dagu-claude-runner:local
pull_policy: never
volumes:
- ${HOME}/.claude:/claude-config
env:
- CLAUDE_CONFIG_DIR=/claude-config
with:
provider: claude
prompt: |
Review this repository.On macOS, Claude Code stores login credentials in the macOS Keychain. A container cannot read the host Keychain by mounting ~/.claude.
In container.volumes, ${HOME} is expanded on the Dagu worker. The /claude-config target is the literal path inside the container.
