-
Notifications
You must be signed in to change notification settings - Fork 0
Create Dockerfile and CI pipeline for Claude Code execution image #317
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| # Build artifacts | ||
| target/ | ||
| *.rlib | ||
| *.d | ||
|
|
||
| # Version control | ||
| .git/ | ||
| .gitignore | ||
|
|
||
| # IDE and editor files | ||
| .idea/ | ||
| .vscode/ | ||
| *.swp | ||
| *.swo | ||
| *~ | ||
|
|
||
| # OS files | ||
| .DS_Store | ||
| Thumbs.db | ||
|
|
||
| # Environment and secrets | ||
| .env | ||
| .env.* | ||
| secrets/ | ||
|
|
||
| # Documentation build output | ||
| docs/book/ | ||
|
|
||
| # CI/CD | ||
| .github/ | ||
|
|
||
| # Node modules (if any local tooling) | ||
| node_modules/ | ||
|
|
||
| # Test databases and temp files | ||
| *.db | ||
| *.db-shm | ||
| *.db-wal | ||
|
|
||
| # UI build artifacts | ||
| ui/node_modules/ | ||
| ui/dist/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| name: Docker — Claude Code Image | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| paths: | ||
| - "docker/claude-code/**" | ||
| - ".github/workflows/docker-claude-code.yml" | ||
| pull_request: | ||
| branches: [main] | ||
| paths: | ||
| - "docker/claude-code/**" | ||
| - ".github/workflows/docker-claude-code.yml" | ||
| release: | ||
| types: [published] | ||
| workflow_dispatch: | ||
|
|
||
| env: | ||
| REGISTRY: ghcr.io | ||
| IMAGE_NAME: geoffjay/agentd-claude | ||
|
|
||
| jobs: | ||
| build: | ||
| name: Build & Push | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v3 | ||
|
|
||
| - name: Set up QEMU (for multi-platform builds) | ||
| uses: docker/setup-qemu-action@v3 | ||
|
|
||
| - name: Log in to GitHub Container Registry | ||
| if: github.event_name != 'pull_request' | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| registry: ${{ env.REGISTRY }} | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Extract metadata (tags, labels) | ||
| id: meta | ||
| uses: docker/metadata-action@v5 | ||
| with: | ||
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | ||
| tags: | | ||
| # latest on main branch pushes | ||
| type=raw,value=latest,enable={{is_default_branch}} | ||
| # short SHA on every build | ||
| type=sha,prefix=sha- | ||
| # semver tags on releases (v1.2.3 → 1.2.3, 1.2, 1) | ||
| type=semver,pattern={{version}} | ||
| type=semver,pattern={{major}}.{{minor}} | ||
| type=semver,pattern={{major}} | ||
|
|
||
| - name: Build and push | ||
| uses: docker/build-push-action@v6 | ||
| with: | ||
| context: docker/claude-code | ||
| file: docker/claude-code/Dockerfile | ||
| platforms: linux/amd64,linux/arm64 | ||
| push: ${{ github.event_name != 'pull_request' }} | ||
| tags: ${{ steps.meta.outputs.tags }} | ||
| labels: ${{ steps.meta.outputs.labels }} | ||
| cache-from: type=gha | ||
| cache-to: type=gha,mode=max | ||
|
|
||
| # NOTE: This only verifies the amd64 variant. The arm64 layer is built | ||
| # and pushed but not smoke-tested here because ubuntu-latest is amd64. | ||
| # A future improvement could add a QEMU-based arm64 verify step. | ||
| - name: Verify image (amd64) | ||
| if: github.event_name != 'pull_request' | ||
| run: | | ||
| docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${GITHUB_SHA::7} | ||
| docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${GITHUB_SHA::7} --version |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| # agentd — top-level build automation | ||
| # | ||
| # Usage: | ||
| # make help Show available targets | ||
| # make build Build the Rust workspace | ||
| # make test Run all tests | ||
| # make docker-build-claude Build the Claude Code Docker image locally | ||
|
|
||
| .PHONY: help build test clippy fmt fmt-fix docker-build-claude docker-build-claude-multiarch docker-run-claude | ||
|
|
||
| # Default image name — matches the DEFAULT_IMAGE constant in crates/wrap/src/docker.rs | ||
| CLAUDE_IMAGE ?= agentd-claude:latest | ||
|
|
||
| help: ## Show this help message | ||
| @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ | ||
| awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-24s\033[0m %s\n", $$1, $$2}' | ||
|
|
||
| # ── Rust ───────────────────────────────────────────────────────────── | ||
|
|
||
| build: ## Build the Rust workspace | ||
| cargo build --workspace | ||
|
|
||
| test: ## Run all workspace tests | ||
| cargo test --workspace | ||
|
|
||
| clippy: ## Run clippy lints | ||
| cargo clippy --workspace -- -D warnings | ||
|
|
||
| fmt: ## Check formatting | ||
| cargo fmt --all -- --check | ||
|
|
||
| fmt-fix: ## Auto-fix formatting | ||
| cargo fmt --all | ||
|
|
||
| # ── Docker ─────────────────────────────────────────────────────────── | ||
|
|
||
| docker-build-claude: ## Build the Claude Code agent Docker image locally | ||
| docker build -t $(CLAUDE_IMAGE) docker/claude-code/ | ||
|
|
||
| docker-build-claude-multiarch: ## Build multi-platform Claude Code image (requires buildx) | ||
| docker buildx build \ | ||
| --platform linux/amd64,linux/arm64 \ | ||
| -t $(CLAUDE_IMAGE) \ | ||
| docker/claude-code/ | ||
|
|
||
| docker-run-claude: ## Run claude --version in the agent image (smoke test) | ||
| docker run --rm $(CLAUDE_IMAGE) --version | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| # syntax=docker/dockerfile:1 | ||
| # | ||
| # Claude Code agent execution image for agentd. | ||
| # | ||
| # This image provides a minimal environment for running the Claude Code CLI | ||
| # inside Docker containers managed by the agentd orchestrator's DockerBackend. | ||
| # | ||
| # Build: | ||
| # docker build -t agentd-claude:latest docker/claude-code/ | ||
| # | ||
| # Run (requires ANTHROPIC_API_KEY): | ||
| # docker run --rm -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" agentd-claude:latest --version | ||
| # | ||
| # Usage with agentd: | ||
| # The orchestrator's DockerBackend creates containers from this image | ||
| # automatically. API keys are passed as environment variables at runtime — | ||
| # nothing secret is baked into the image. | ||
|
|
||
geoffjay marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| FROM node:22-slim | ||
|
|
||
| # ── System dependencies ─────────────────────────────────────────────── | ||
| # Install common dev tools needed by Claude Code and agent workflows. | ||
| # - git: repository operations, diffs, commits | ||
| # - ca-certificates: HTTPS connections to APIs and registries | ||
| # - curl: health checks, API calls, downloading tools | ||
| # - jq: JSON processing in shell scripts | ||
| # - openssh-client: git operations over SSH | ||
| RUN apt-get update && \ | ||
| apt-get install -y --no-install-recommends \ | ||
| git \ | ||
| ca-certificates \ | ||
| curl \ | ||
| jq \ | ||
| openssh-client \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # ── Claude Code CLI ────────────────────────────────────────────────── | ||
| # Install globally so it's available on PATH for all users. | ||
| # Pin the version for reproducible builds. Update deliberately or via | ||
| # Renovate / Dependabot when a new release is needed. | ||
| ARG CLAUDE_CODE_VERSION=0.2.70 | ||
| RUN npm install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION} && \ | ||
| npm cache clean --force | ||
|
|
||
| # ── Non-root user ──────────────────────────────────────────────────── | ||
| # The node:22-slim base image already has a `node` user at UID 1000. | ||
| # Rename it to `agent` for clarity and to match DockerBackend's default | ||
| # user (1000:1000). Using usermod/groupmod avoids the "UID already | ||
| # exists" error from useradd. | ||
| RUN groupmod --new-name agent node && \ | ||
| usermod --login agent --home /home/agent --move-home --comment "agentd agent" node | ||
|
|
||
| # ── Git configuration ──────────────────────────────────────────────── | ||
| # Set safe.directory so git works in bind-mounted /workspace regardless | ||
| # of ownership. Also set a default identity for commits made by agents. | ||
| RUN git config --system safe.directory /workspace && \ | ||
| git config --system user.email "agent@agentd.local" && \ | ||
| git config --system user.name "agentd agent" | ||
|
|
||
| # ── Workspace ──────────────────────────────────────────────────────── | ||
| RUN mkdir -p /workspace && chown agent:agent /workspace | ||
| WORKDIR /workspace | ||
|
|
||
| # ── Runtime ────────────────────────────────────────────────────────── | ||
| USER agent | ||
|
|
||
| # Verify the CLI is installed and accessible. | ||
| RUN claude --version | ||
|
|
||
| CMD ["claude"] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| # Claude Code Agent Image | ||
|
|
||
| Docker image for running Claude Code CLI agents inside containers managed by | ||
| the agentd orchestrator's `DockerBackend`. | ||
|
|
||
| ## Quick Start | ||
|
|
||
| ```bash | ||
| # Build locally | ||
| make docker-build-claude | ||
|
|
||
| # Or build directly | ||
| docker build -t agentd-claude:latest docker/claude-code/ | ||
|
|
||
| # Verify | ||
| docker run --rm agentd-claude:latest --version | ||
|
|
||
| # Run with API key | ||
| docker run --rm \ | ||
| -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \ | ||
| -v "$(pwd):/workspace" \ | ||
| agentd-claude:latest --version | ||
| ``` | ||
|
|
||
| ## What's Included | ||
|
|
||
| | Component | Purpose | | ||
| |-----------|---------| | ||
| | Node.js 22 (slim) | Runtime for Claude Code CLI | | ||
| | `@anthropic-ai/claude-code` | The Claude Code CLI itself | | ||
| | `git` | Repository operations | | ||
| | `curl` | HTTP requests, health checks | | ||
| | `jq` | JSON processing | | ||
| | `openssh-client` | Git over SSH | | ||
| | `ca-certificates` | TLS certificate validation | | ||
|
|
||
| ## Security | ||
|
|
||
| - **Non-root**: Runs as `agent` (UID 1000) by default | ||
| - **No secrets**: API keys are passed at runtime via environment variables | ||
| - **Minimal base**: Uses `node:22-slim` to reduce attack surface | ||
|
|
||
| ## Customization | ||
|
|
||
| ### Adding tools | ||
|
|
||
| Create a derived Dockerfile: | ||
|
|
||
| ```dockerfile | ||
| FROM ghcr.io/geoffjay/agentd-claude:latest | ||
|
|
||
| USER root | ||
| RUN apt-get update && apt-get install -y --no-install-recommends \ | ||
| python3 \ | ||
| ripgrep \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
| USER agent | ||
| ``` | ||
|
|
||
| ### Using a different base image | ||
|
|
||
| Fork this Dockerfile and change the `FROM` line. The key requirements are: | ||
| - Node.js (for the Claude Code CLI) | ||
| - A non-root user with UID 1000 | ||
| - `/workspace` as the working directory | ||
|
|
||
| ## Image Tags | ||
|
|
||
| | Tag | Description | | ||
| |-----|-------------| | ||
| | `latest` | Latest build from `main` branch | | ||
| | `sha-<hash>` | Pinned to a specific git commit | | ||
| | `v1.2.3` | Pinned to a semver release tag | | ||
|
|
||
| ## How It Works with agentd | ||
|
|
||
| The `DockerBackend` in the orchestrator creates containers from this image: | ||
|
|
||
| 1. The orchestrator calls `docker create` with this image | ||
| 2. The host project directory is bind-mounted to `/workspace` | ||
| 3. API keys are passed as environment variables | ||
| 4. The `NetworkPolicy` controls container networking | ||
| 5. Claude Code connects back to the orchestrator via WebSocket | ||
|
|
||
| The container's entrypoint is `claude`, and the orchestrator passes additional | ||
| arguments (like `--sdk-url`, `--output-format stream-json`) via `docker exec`. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.