Skip to content

feat: Add containerized Claude agent#92

Open
msager27 wants to merge 3 commits into
mainfrom
claude-agent
Open

feat: Add containerized Claude agent#92
msager27 wants to merge 3 commits into
mainfrom
claude-agent

Conversation

@msager27
Copy link
Copy Markdown

@msager27 msager27 commented May 5, 2026

Description

Add containerized Claude agent. This is the first in a series of building blocks to enable Claude Code agent deployment and operation on RHOAI with vLLM/OGX interoperability. With this PR, a user can build, deploy, and run Claude on RHOAI. A user can also run locally with podman. Some additional notes:

  • Either an Anthropic api key or Vertex AI (with a service account key) is needed to use Claude. This PR includes deployment yamls for both, plus setup and usage instructions in README.md. Since I don't have an api key, I've only tested it with Vertex.
  • Initial support for skills and mcp config is provided, but is mainly a placeholder for now. More to come.
  • Non-Anthropic backends like vLLM/OGX are not yet tested. This will also come later.

cc @aakankshaduggal

Jira Ticket

RHAIENG-4737

Testing

After deploying Claude on RHOAI, testing can be done using oc exec (see README for full commands and instructions). Longer term, we need to investigate some type of UI on RHOAI.

  • Test claude interactively on RHOAI
  • Test claude non-interactively (-p option) on RHOAI
  • Test claude in debug mode on RHOAI and monitor logs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@msager27 msager27 requested a review from aakankshaduggal May 5, 2026 20:38
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 1e85b08c-5ea6-4a41-8b4c-7272569cbb54

📥 Commits

Reviewing files that changed from the base of the PR and between 55cd3a2 and d3dc149.

📒 Files selected for processing (5)
  • agents/claude/claude_agent/Containerfile
  • agents/claude/claude_agent/README.md
  • agents/claude/claude_agent/deployment-vertex.yaml
  • agents/claude/claude_agent/deployment.yaml
  • agents/claude/claude_agent/entrypoint.sh
✅ Files skipped from review due to trivial changes (1)
  • agents/claude/claude_agent/README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • agents/claude/claude_agent/deployment-vertex.yaml
  • agents/claude/claude_agent/deployment.yaml

📝 Walkthrough

Walkthrough

This PR adds a UBI10-based Containerfile and entrypoint for running the pinned @anthropic-ai/claude-code CLI, OpenShift/Kubernetes manifests for Anthropic and Vertex AI deployments (ImageStream/BuildConfig/ConfigMaps/PVC/Deployment/Service), and a README with step-by-step deployment and cleanup instructions.

Changes

Claude Code OpenShift Container Deployment

Layer / File(s) Summary
Container Image & Runtime Setup
agents/claude/claude_agent/Containerfile, agents/claude/claude_agent/entrypoint.sh
Containerfile builds a UBI10-minimal image, creates a non-root OpenShift-compatible user, installs a pinned @anthropic-ai/claude-code npm package, configures runtime dirs and DISABLE_AUTOUPDATER, and sets WORKDIR/ENTRYPOINT/CMD. Entrypoint script validates auth and model inputs, builds MCP and skills args, writes ~/.claude/env.sh and claude-run wrapper, and dispatches to claude or arbitrary commands.
Kubernetes / OpenShift Manifests
agents/claude/claude_agent/deployment.yaml, agents/claude/claude_agent/deployment-vertex.yaml
Adds ImageStream and BuildConfig for binary builds, ConfigMaps for MCP/skills/Vertex settings, PVC for /workspace, Deployments (Anthropic and Vertex variants) wiring secrets/configs and securityContext restrictions, and optional Services exposing port 8080.
Deployment Documentation
agents/claude/claude_agent/README.md
Comprehensive guide with prerequisites, Option A (Anthropic API key) and Option B (Vertex AI) step-by-step deployment flows, local build/run smoke tests, debug tips, and cleanup commands.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant OC_Build as "OpenShift Build/CLI"
  participant Registry
  participant Cluster as "Deployment / Pod"
  User->>OC_Build: start build (Containerfile)
  OC_Build->>Registry: push image -> ImageStream
  Registry->>Cluster: deploy image to Deployment
  Cluster->>Cluster: Pod starts -> entrypoint.sh configures claude
  Cluster->>ExternalAPI: claude uses Anthropic/Vertex credentials
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding a containerized Claude agent, which is the primary focus of all file additions in the changeset.
Description check ✅ Passed The description provides relevant context about the containerized Claude agent, its purpose for RHOAI deployment, supported authentication methods, testing approach, and future plans.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude-agent

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the size/l label May 5, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
agents/claude/claude_agent/entrypoint.sh (1)

102-103: ⚡ Quick win

Array serialized as space-joined string causes word-splitting fragility

MCP_ARGS="${mcp_args[*]:-}" flattens the array into a single space-delimited string. It is then re-expanded unquoted (args+=(${MCP_ARGS})) to recover the elements. This breaks silently if any element (e.g., a file path) contains a space. The same pattern repeats with CLAUDE_EXTRA_ARGS (lines 163, 191).

Since all functions run in the same shell process, exporting through env vars is unnecessary. Using a global array avoids the serialization entirely:

♻️ Proposed refactor: use global arrays instead of exported strings
+# Global arrays shared across functions (avoids word-splitting via export)
+MCP_ARGS_ARRAY=()
+CLAUDE_EXTRA_ARGS_ARRAY=()
+
 setup_mcp() {
-    local mcp_args=()
+    MCP_ARGS_ARRAY=()
     ...
-    mcp_args+=("--mcp-config" "${MCP_CONFIG_FILE}")
+    MCP_ARGS_ARRAY+=("--mcp-config" "${MCP_CONFIG_FILE}")
     ...
-    export MCP_ARGS="${mcp_args[*]:-}"
 }

 build_claude_args() {
     local args=()
-    if [[ -n "${MCP_ARGS:-}" ]]; then
-        # shellcheck disable=SC2206
-        args+=(${MCP_ARGS})
-    fi
+    if [[ ${`#MCP_ARGS_ARRAY`[@]} -gt 0 ]]; then
+        args+=("${MCP_ARGS_ARRAY[@]}")
+    fi
     ...
-    export CLAUDE_EXTRA_ARGS="${args[*]:-}"
+    CLAUDE_EXTRA_ARGS_ARRAY=("${args[@]}")
 }

 # In main():
-    exec claude ${CLAUDE_EXTRA_ARGS} "$@"
+    exec claude "${CLAUDE_EXTRA_ARGS_ARRAY[@]}" "$@"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agents/claude/claude_agent/entrypoint.sh` around lines 102 - 103, The code
flattens arrays into space-joined env strings (MCP_ARGS, CLAUDE_EXTRA_ARGS) and
later re-expands them unquoted causing word-splitting; instead stop exporting
those env vars and keep/use bash arrays directly: remove export MCP_ARGS and
export CLAUDE_EXTRA_ARGS/claude_extra_args, retain the original arrays (mcp_args
and claude_extra_args) in the shared shell and change all re-expansions to
preserve elements with args+=("${mcp_args[@]}") and
args+=("${claude_extra_args[@]}") (and any other places using
args+=(${MCP_ARGS}) or args+=(${CLAUDE_EXTRA_ARGS}) ), ensuring elements with
spaces are preserved.
agents/claude/claude_agent/Containerfile (1)

37-38: ⚡ Quick win

NODE_VERSION ARG is defined but never used

ARG NODE_VERSION=22 has no effect on the microdnf install nodejs invocation, so --build-arg NODE_VERSION=18 (or any value) is silently ignored. The Node version installed is whatever UBI 10's repos provide.

Either remove the ARG, or wire it into the install step (e.g., via a NodeSource/NVM setup or a nodejs:${NODE_VERSION} module stream call with microdnf module enable).

-# Node.js version (major version, installs latest in that series)
-ARG NODE_VERSION=22
-
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agents/claude/claude_agent/Containerfile` around lines 37 - 38, ARG
NODE_VERSION is declared but unused; either remove it or wire it into the
install. To fix, either delete the ARG NODE_VERSION=22 from the Containerfile,
or change the install sequence to use the argument (for example by running the
module stream command that binds to the arg: use "microdnf module enable
nodejs:${NODE_VERSION}" then "microdnf install nodejs" or otherwise source Node
from NodeSource/NVM using NODE_VERSION). Update the Containerfile lines around
the existing "ARG NODE_VERSION=22" and the "microdnf install nodejs" invocation
to reflect the chosen approach so --build-arg NODE_VERSION takes effect.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@agents/claude/claude_agent/deployment.yaml`:
- Around line 122-123: The SKIP_PERMISSIONS environment variable is currently
hardcoded to "true", enabling --dangerously-skip-permissions by default; change
the default value to "false" for the SKIP_PERMISSIONS env var in the manifest(s)
(look for the SKIP_PERMISSIONS env entry in the deployment YAML and the
equivalent in the vertex deployment) so operators must explicitly opt-in to
dangerous behavior, and add a README note documenting that setting
SKIP_PERMISSIONS to "true" enables --dangerously-skip-permissions (risk:
filesystem write bypass) and must be used only in sandboxed environments.

In `@agents/claude/claude_agent/entrypoint.sh`:
- Around line 96-99: MCP_CONFIG_JSON is treated as inline JSON but is passed
directly to mcp_args as "--mcp-config" which expects a filesystem path; instead,
create a temporary file (e.g., via mktemp), write MCP_CONFIG_JSON into it, push
that temp path onto mcp_args (same place you currently append
"${MCP_CONFIG_JSON}"), and ensure the temp file is removed on exit (use trap to
unlink). Also preserve existing validation logic by checking the temp file
exists before appending and reference the symbols MCP_CONFIG_JSON, mcp_args,
--mcp-config, and MCP_CONFIG_FILE so the change mirrors the established
file-based flow.

In `@agents/claude/claude_agent/README.md`:
- Around line 281-291: Update the Cleanup section in README.md to include the
Vertex AI (Option B) resource names and commands in addition to the existing
Option A names; specifically add oc delete commands for the Vertex-specific
deployment, buildconfig, imagestream, secret(s), configmap(s) and PVC (e.g.,
names prefixed or suffixed with "vertex" such as claude-vertex-deployment,
claude-vertex-buildconfig, claude-vertex-imagestream, claude-vertex-credentials,
claude-vertex-mcp-config, claude-vertex-skills, claude-vertex-workspace) and
clarify which commands apply to Option A (claude-code, claude-credentials,
claude-mcp-config, claude-skills, claude-workspace) vs Option B so users run the
correct oc delete lines for their chosen option.

---

Nitpick comments:
In `@agents/claude/claude_agent/Containerfile`:
- Around line 37-38: ARG NODE_VERSION is declared but unused; either remove it
or wire it into the install. To fix, either delete the ARG NODE_VERSION=22 from
the Containerfile, or change the install sequence to use the argument (for
example by running the module stream command that binds to the arg: use
"microdnf module enable nodejs:${NODE_VERSION}" then "microdnf install nodejs"
or otherwise source Node from NodeSource/NVM using NODE_VERSION). Update the
Containerfile lines around the existing "ARG NODE_VERSION=22" and the "microdnf
install nodejs" invocation to reflect the chosen approach so --build-arg
NODE_VERSION takes effect.

In `@agents/claude/claude_agent/entrypoint.sh`:
- Around line 102-103: The code flattens arrays into space-joined env strings
(MCP_ARGS, CLAUDE_EXTRA_ARGS) and later re-expands them unquoted causing
word-splitting; instead stop exporting those env vars and keep/use bash arrays
directly: remove export MCP_ARGS and export CLAUDE_EXTRA_ARGS/claude_extra_args,
retain the original arrays (mcp_args and claude_extra_args) in the shared shell
and change all re-expansions to preserve elements with args+=("${mcp_args[@]}")
and args+=("${claude_extra_args[@]}") (and any other places using
args+=(${MCP_ARGS}) or args+=(${CLAUDE_EXTRA_ARGS}) ), ensuring elements with
spaces are preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 959e1b61-76bd-418b-8cb3-6676b921c807

📥 Commits

Reviewing files that changed from the base of the PR and between 49f1245 and 55cd3a2.

📒 Files selected for processing (5)
  • agents/claude/claude_agent/Containerfile
  • agents/claude/claude_agent/README.md
  • agents/claude/claude_agent/deployment-vertex.yaml
  • agents/claude/claude_agent/deployment.yaml
  • agents/claude/claude_agent/entrypoint.sh

Comment thread agents/claude/claude_agent/deployment.yaml Outdated
Comment thread agents/claude/claude_agent/entrypoint.sh
Comment thread agents/claude/claude_agent/README.md
@aakankshaduggal aakankshaduggal requested review from Nehanth May 6, 2026 18:11
Copy link
Copy Markdown

@aakankshaduggal aakankshaduggal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review by Claude with Aakanksha's manual approval

Tested this PR on ROSA using the Vertex AI path for RHAIENG-4739. Image builds cleanly, runs under restricted-v2 SCC, and Claude Code responds to prompts. Nice work on the Containerfile and entrypoint structure.

4 inline comments below with issues found during testing. OGX integration testing is blocked on RHAIENG-4743.

Test Results (RHAIENG-4739 partial)

Criteria Result
Image deployed as pod on OpenShift PASS
Pod runs under restricted-v2 SCC PASS
Claude Code starts and accepts input PASS
No security policy violations in logs PASS
Process spawning (bash) works PASS
Non-root user (OpenShift random UID) PASS
Workspace writable via PVC PASS
OGX backend integration BLOCKED (waiting on RHAIENG-4743)

Comment thread agents/claude/claude_agent/entrypoint.sh Outdated
Comment thread agents/claude/claude_agent/entrypoint.sh Outdated
Comment thread agents/claude/claude_agent/entrypoint.sh
Comment thread agents/claude/claude_agent/deployment-vertex.yaml
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@msager27
Copy link
Copy Markdown
Author

msager27 commented May 8, 2026

@aakankshaduggal Thanks for the review! I've pushed some fixes that should address everything.

@hmoghani
Copy link
Copy Markdown
Contributor

Could you also update the main directory README file and add reference to the claude agent?

@jwm4
Copy link
Copy Markdown

jwm4 commented May 14, 2026

Licensing note: README should warn against distributing built images

The Containerfile installs Claude Code at build time, so the resulting container image contains Anthropic's proprietary binary (the license is "All rights reserved," subject to their commercial terms). Users building the image themselves is fine, but the README should explicitly note that the built images should not be redistributed, since they contain proprietary closed-source software.

npm install is no longer the recommended method

Anthropic now recommends their native installer over npm. The CLI itself warns users to switch when launched from an npm install. They also publish a dnf repo for RHEL/Fedora, which might be a more natural fit for a UBI base. See also anthropics/claude-code#24568, which flagged the same npm issue in Anthropic's own devcontainer reference.

The Containerfile should replace:

npm install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}

with the native installer:

curl -fsSL https://claude.ai/install.sh | bash

This also removes the need for npm as a build dependency.


This comment was drafted by Claude Code under the supervision of Bill Murdock.

Copy link
Copy Markdown

@jwm4 jwm4 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See earlier comment.

…ng note.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@msager27 msager27 requested a review from jwm4 May 15, 2026 19:15
@msager27
Copy link
Copy Markdown
Author

@jwm4 We now use the native installer. Also, I've added a licensing notice. Thanks for the review!

Copy link
Copy Markdown

@jwm4 jwm4 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested this myself, but all my concerns are addressed so it looks good to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants