Last updated: Aug 12, 2025, 01:09 PM UTC

Claude CLI Docker Integration Issues Analysis

Generated: 2025-01-10 UTC
Purpose: Comprehensive analysis of Claude CLI integration issues in Docker environments
Impact: Critical for Sliplane and containerized deployments


Executive Summary

The Claude CLI integration in Docker environments faces multiple architectural challenges that prevent proper functionality in production deployments, particularly on Sliplane. These issues stem from fundamental mismatches between local development assumptions and containerized runtime realities.

Core Problems

  1. Workspace Path Mismatch: Files created in one location, Claude CLI expects them elsewhere
  2. Installation Failures: Complex symlink logic fails in Alpine Linux containers
  3. Environment Detection: Inconsistent Docker environment detection across codebase
  4. Permission Conflicts: File system permissions differ between local and container environments
  5. Architecture Issues: Forced AMD64 builds may not match deployment platforms

Impact

  • Claude CLI fails to start or find projects in Sliplane deployments
  • Workspace initialization creates directories in wrong locations
  • API key configuration doesn't persist correctly
  • Sessions cannot be resumed after container restarts

Architecture Mismatch Issues

Current Architecture Assumptions

graph TB subgraph "Local Development" LD[Local Docker] LW[~/.claude/projects/] LC[Claude CLI Direct] end subgraph "Production (Sliplane)" PD[Sliplane Docker] PW[/app/workspaces/] PC[Claude CLI via Node] end subgraph "Path Conflicts" WM[workspace-manager.js] CLI[claude-cli.js] DI[docker-init.js] end LD --> LW PD --> PW WM --> LW CLI --> PW DI --> Both[Tries to Bridge]

Key Differences

Component Local Docker Sliplane Docker Issue
Workspace Path $HOME/.claude/projects/ /app/workspaces/ Mismatch in creation vs usage
Claude CLI Install Global npm install Manual symlink creation Symlink may fail or point wrong
Environment Detection RUNNING_IN_DOCKER Multiple checks Inconsistent detection
File Permissions User-based Volume-based Permission denied errors
Architecture Native Forced AMD64 Platform mismatch

Detailed Issue Analysis

Issue #1: Workspace Path Mismatch

Problem: The workspace manager creates projects in one location while Claude CLI looks for them in another.

Code Evidence:

// workspace-manager.js (lines 24-26)
workspacePath = path.join(process.env.HOME, '.claude/projects', `${sanitizedName}-${projectId}`);
// Creates at: /home/nodejs/.claude/projects/default-workspace

// claude-cli.js (line 45)
if (process.env.RUNNING_IN_DOCKER === 'true') {
    workingDir = `/app/workspaces/${workingDir}`;
}
// Expects at: /app/workspaces/workspace

Impact:

  • Claude CLI cannot find project files
  • Sessions cannot be resumed
  • CLAUDE.md instructions not accessible

Root Cause:

  • Inconsistent path resolution between services
  • docker-init.js attempts to bridge but creates confusion

Issue #2: Claude CLI Installation & Symlink Problems

Problem: The Dockerfile.sliplane contains extensive debugging and manual symlink creation that may fail.

Code Evidence (Dockerfile.sliplane lines 95-141):

# Debug: Comprehensive Claude CLI installation verification
RUN echo "πŸ” Claude CLI Installation Debug:" && \
    # ... 40+ lines of debugging and symlink attempts ...
    ln -sf /usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js /usr/local/bin/claude

Issues:

  1. Manual symlink creation is fragile
  2. Assumes specific file locations that may change with package updates
  3. Complex debugging suggests underlying installation problems
  4. Alpine Linux may handle symlinks differently

Impact:

  • Claude CLI command not found
  • Symlink points to non-existent file
  • Different behavior across Claude CLI versions

Issue #3: Environment Variable Conflicts

Problem: Multiple environment variables control similar behaviors with unclear precedence.

Conflicting Variables:

# Docker detection
RUNNING_IN_DOCKER=true
USE_DOCKER_WORKSPACE=true

# Path configuration
WORKSPACES_PATH=/app/workspaces
CLAUDE_PROJECTS_PATH=/app/workspaces
CLAUDE_HOME=/home/nodejs/.claude

# Actual usage varies
process.env.HOME = /home/nodejs  # But code uses this for paths

Code Confusion (claude-cli.js lines 289-292):

const isDockerEnv = process.env.RUNNING_IN_DOCKER === 'true' || 
                   process.env.USE_DOCKER_WORKSPACE === 'true' ||
                   process.cwd().startsWith('/app') ||
                   process.env.HOME === '/home/nodejs' ||
                   require('fs').existsSync('/.dockerenv');

Impact:

  • Inconsistent behavior across different code paths
  • Difficult to debug which condition triggered
  • May work locally but fail in production

Issue #4: Docker Detection Logic

Problem: Complex Docker detection with multiple fallbacks creates unpredictable behavior.

Detection Methods:

  1. Environment variable checks
  2. Working directory inspection
  3. Home directory pattern matching
  4. Docker indicator file (/.dockerenv)
  5. Different execution methods (execFile vs spawn)

Code Issues (claude-cli.js lines 298-387):

if (isDockerEnv) {
    // Uses execFile with node explicitly
    claudeCommand = '/usr/local/bin/node';
    finalArgs = [claudeScriptPath, ...args];
    claudeProcess = execFile(claudeCommand, finalArgs, spawnOptions);
} else {
    // Uses spawn with 'claude' command
    claudeProcess = spawnFunction('claude', args, spawnOptions);
}

Impact:

  • Different execution paths may have different bugs
  • Hard to reproduce issues consistently
  • Alpine-specific issues with execFile

Issue #5: Platform Architecture Issues

Problem: Build scripts force AMD64 architecture which may not match Sliplane's actual platform.

Code Evidence (push-to-sliplane.sh line 191):

docker buildx build \
    --platform linux/amd64 \  # Forced platform
    -f "$DOCKERFILE" \
    ...

Issues:

  1. Sliplane may run on ARM64 or other architectures
  2. Forced platform can cause performance issues
  3. Native modules compiled for wrong architecture

Impact:

  • Slow performance due to emulation
  • Potential crashes with native modules
  • Increased container size

Root Cause Analysis

Design Assumptions vs Reality

Assumption Reality Consequence
Single workspace path strategy Multiple path resolution strategies Files created in wrong location
npm global install "just works" Alpine Linux requires special handling Claude CLI not accessible
Docker environment is uniform Multiple Docker variants exist Inconsistent behavior
Simple environment detection Complex multi-layered detection needed Unpredictable code paths
AMD64 is universal Cloud platforms use various architectures Performance and compatibility issues

Architectural Debt

  1. Incremental Fixes: Each issue was patched individually rather than redesigning
  2. Multiple Truth Sources: Environment variables, file paths, and detection logic conflict
  3. Debugging Code in Production: Extensive debugging left in production Dockerfile
  4. Assumption Cascade: Each fix assumes previous fixes work correctly

Proposed Solutions

Short-term Fixes (Immediate)

1. Standardize Workspace Paths

// Add to workspace-manager.js
function getWorkspacePath(projectName) {
    if (process.env.WORKSPACES_PATH) {
        return path.join(process.env.WORKSPACES_PATH, projectName);
    }
    return path.join(process.env.HOME, '.claude/projects', projectName);
}

2. Simplify Claude CLI Installation

# Remove complex symlink logic, use npm bin directly
RUN npm install -g @anthropic-ai/claude-code@latest && \
    npm bin -g && \
    ln -sf $(npm bin -g)/claude /usr/local/bin/claude

3. Single Docker Detection Method

// Standardize on one detection method
function isDockerEnvironment() {
    return process.env.RUNNING_IN_DOCKER === 'true';
}

Long-term Solutions (Architectural)

1. Unified Path Resolution Service

Create a single service responsible for all path resolution:

class PathResolver {
    getWorkspacePath(project) { /* ... */ }
    getClaudePath() { /* ... */ }
    getDocumentPath() { /* ... */ }
}

2. Container-First Design

  • Design for containers first, adapt for local development
  • Use volume mounts consistently
  • Avoid home directory assumptions

3. Platform-Agnostic Builds

# docker-compose.yml
services:
  sasha:
    build:
      platforms:
        - linux/amd64
        - linux/arm64

4. Configuration Over Detection

Replace complex detection with explicit configuration:

// config.js
export default {
    environment: process.env.DEPLOYMENT_ENV || 'local',
    paths: {
        workspace: process.env.WORKSPACE_PATH || '/app/workspaces',
        claude: process.env.CLAUDE_PATH || '/home/nodejs/.claude'
    }
}

Testing & Validation

Health Check Recommendations

1. Claude CLI Availability Check

// Add to health endpoint
async function checkClaudeCLI() {
    try {
        const { execSync } = require('child_process');
        const result = execSync('which claude', { encoding: 'utf8' });
        return { available: true, path: result.trim() };
    } catch (error) {
        return { available: false, error: error.message };
    }
}

2. Workspace Path Validation

async function validateWorkspacePaths() {
    const paths = {
        configured: process.env.WORKSPACES_PATH,
        expected: '/app/workspaces',
        actual: await getActualWorkspacePath()
    };
    return {
        valid: paths.configured === paths.actual,
        paths
    };
}

3. Environment Consistency Check

function checkEnvironmentConsistency() {
    const checks = {
        dockerEnv: process.env.RUNNING_IN_DOCKER === 'true',
        dockerWorkspace: process.env.USE_DOCKER_WORKSPACE === 'true',
        pathsAlign: process.env.WORKSPACES_PATH === process.env.CLAUDE_PROJECTS_PATH,
        dockerFile: fs.existsSync('/.dockerenv')
    };
    return {
        consistent: Object.values(checks).every(v => v === checks.dockerEnv),
        checks
    };
}

Deployment Verification Script

#!/bin/bash
# verify-claude-deployment.sh

echo "πŸ” Verifying Claude CLI Deployment"

# Check Claude CLI installation
if command -v claude &> /dev/null; then
    echo "βœ… Claude CLI found at: $(which claude)"
    claude --version
else
    echo "❌ Claude CLI not found"
    exit 1
fi

# Check workspace paths
echo "πŸ“ Checking workspace paths:"
echo "  WORKSPACES_PATH: $WORKSPACES_PATH"
echo "  CLAUDE_PROJECTS_PATH: $CLAUDE_PROJECTS_PATH"
[ -d "$WORKSPACES_PATH" ] && echo "  βœ… Workspace directory exists" || echo "  ❌ Workspace directory missing"

# Test Claude CLI execution
echo "πŸ§ͺ Testing Claude CLI execution:"
echo "test" | claude --print "echo hello" --output-format stream-json &> /tmp/claude-test.log
[ $? -eq 0 ] && echo "  βœ… Claude CLI executes" || echo "  ❌ Claude CLI execution failed"

Impact Assessment

Current State Impact

  • Severity: Critical
  • Affected Deployments: All containerized environments
  • User Impact: Claude CLI features completely unavailable
  • Business Impact: Core product functionality broken in production

Post-Fix Benefits

  • Consistent behavior across all environments
  • Simplified debugging and maintenance
  • Faster deployment cycles
  • Improved reliability

Migration Path

Phase 1: Immediate Patches (1-2 days)

  1. Fix workspace path resolution
  2. Simplify Claude CLI installation
  3. Add health checks

Phase 2: Refactoring (1 week)

  1. Implement PathResolver service
  2. Standardize environment detection
  3. Update all path references

Phase 3: Architecture Update (2 weeks)

  1. Container-first redesign
  2. Multi-platform builds
  3. Comprehensive testing suite

References


Resolution Implemented

Fixes Applied (2025-08-10)

  1. Workspace Path Resolution

    • Created symlink from /home/nodejs/.claude/projects to /app/workspaces
    • All Claude CLI operations now use unified workspace directory
    • Prevents duplicate workspace creation
  2. Claude CLI Installation

    • Simplified installation using npm install -g @anthropic-ai/claude-code@latest
    • Proper symlink creation in Dockerfile
    • Version 1.0.72 successfully deployed
  3. Docker Environment Detection

    • Simplified to single RUNNING_IN_DOCKER=true check
    • Added USE_DOCKER_WORKSPACE=true for redundancy
    • Removed complex multi-layered detection
  4. Environment Variables

    • All critical variables properly set in Dockerfile
    • docker-entrypoint.sh ensures runtime configuration
    • Consistent path resolution across services
  5. Health Checks

    • Created verification scripts for deployment validation
    • Health endpoint configured in Dockerfile
    • Monitoring scripts available

Final Solution Architecture

graph TB subgraph "Workspace Structure" WS[/app/workspaces/] WW[/app/workspaces/workspace/] CP[/home/nodejs/.claude/projects] end subgraph "Claude CLI" CLI[claude command] API[Claude API] end CP -->|symlink| WS CLI --> CP CLI --> WW WW --> API

Verification Results

  • Claude CLI installed and accessible at /usr/local/bin/claude
  • Environment variables correctly set
  • Workspace symlink functioning properly
  • No duplicate workspace directories
  • All operations use /app/workspaces/ as base

Checklist for Resolution

  • Standardize workspace path resolution
  • Fix Claude CLI installation in Alpine
  • Simplify Docker environment detection
  • Remove platform-specific build constraints
  • Add comprehensive health checks
  • Test in actual Sliplane environment
  • Update documentation with findings
  • Create verification scripts
  • Monitor production deployments
  • Document lessons learned

Last Updated: 2025-08-10
Status: Resolved
Owner: DevOps Team
Resolution: Successfully deployed to Sliplane with all issues fixed