Claude Code SDK

The Claude Code SDK provides Java integration with Anthropic’s Claude Code CLI, enabling autonomous coding capabilities in Spring applications.

1. Overview

Claude Code is Anthropic’s autonomous coding agent that can read, write, and execute code across entire codebases. The Spring AI Claude Code integration makes it easy to incorporate these capabilities into Java applications.

2. Installation

2.1. Prerequisites

  1. Install Claude Code CLI:

    npm install -g @anthropic-ai/claude-code
  2. Set API Key:

    export ANTHROPIC_API_KEY="your-api-key-here"

    Get your API key from the Anthropic Console.

  3. Verify Installation:

    claude --version

2.2. Maven Dependencies

Add the following dependencies to your pom.xml:

<dependencies>
    <!-- Core AgentClient API -->
    <dependency>
        <groupId>org.springaicommunity.agents</groupId>
        <artifactId>spring-ai-agent-client</artifactId>
        <version>0.1.0-SNAPSHOT</version>
    </dependency>

    <!-- Claude Code integration -->
    <dependency>
        <groupId>org.springaicommunity.agents</groupId>
        <artifactId>spring-ai-claude-code</artifactId>
        <version>0.1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

3. Basic Usage

3.1. Quick Start

import org.springaicommunity.agents.client.AgentClient;
import org.springaicommunity.agents.client.AgentClientResponse;
import org.springaicommunity.agents.claudecode.ClaudeCodeAgentModel;
import org.springaicommunity.agents.claudecode.ClaudeCodeAgentOptions;
import org.springaicommunity.agents.claudecode.sdk.ClaudeCodeClient;

import java.nio.file.Paths;

public class ClaudeCodeExample {
    public static void main(String[] args) {
        // 1. Create the Claude Code client
        ClaudeCodeClient claudeClient = ClaudeCodeClient.create(
            Paths.get(System.getProperty("user.dir"))
        );

        // 2. Configure agent options
        ClaudeCodeAgentOptions options = ClaudeCodeAgentOptions.builder()
            .model("claude-sonnet-4-0")
            .yolo(true)
            .build();

        // 3. Create the agent model
        ClaudeCodeAgentModel agentModel = new ClaudeCodeAgentModel(claudeClient, options);

        // 4. Create AgentClient
        AgentClient agentClient = AgentClient.create(agentModel);

        // 5. Execute a goal
        AgentClientResponse response = agentClient.run(
            "Create a simple Calculator class with add, subtract, multiply, and divide methods"
        );

        System.out.println("Result: " + response.getResult());
        System.out.println("Success: " + response.isSuccessful());
    }
}

4. Configuration

4.1. ClaudeCodeClient

The ClaudeCodeClient manages communication with the Claude CLI:

// Create with default working directory
ClaudeCodeClient client = ClaudeCodeClient.create();

// Create with specific working directory
Path projectPath = Paths.get("/path/to/project");
ClaudeCodeClient client = ClaudeCodeClient.create(projectPath);

// Create with custom Claude command path
ClaudeCodeClient client = ClaudeCodeClient.create(
    projectPath,
    "/custom/path/to/claude"
);

4.2. ClaudeCodeAgentOptions

Configure Claude-specific behavior:

ClaudeCodeAgentOptions options = ClaudeCodeAgentOptions.builder()
    // Model selection
    .model("claude-sonnet-4-0")  // or "claude-haiku-4-0"

    // Execution settings
    .yolo(true)                           // Allow modifications
    .timeout(Duration.ofMinutes(10))      // Execution timeout
    .maxTokens(8192)                      // Response length limit

    // Output preferences
    .verbose(true)                        // Detailed logging
    .outputFormat("json")                 // Structured output

    .build();

4.3. Model Options

Available Claude models:

Model Description Best For

claude-sonnet-4-0

Latest Sonnet model with enhanced coding capabilities

Complex refactoring, large codebases, architectural changes

claude-haiku-4-0

Faster model optimized for speed

Quick fixes, simple tasks, rapid prototyping

claude-opus-4-0

Most capable model for complex reasoning

Complex algorithms, system design, challenging debugging

5. Advanced Features

5.1. Working Directory Management

Claude Code operates within a specific directory context:

// Configure working directory via client
ClaudeCodeClient client = ClaudeCodeClient.create(
    Paths.get("/path/to/microservice")
);

// Or via AgentClient fluent API
AgentClientResponse response = agentClient
    .goal("Add validation to the UserController")
    .workingDirectory("/path/to/microservice")
    .run();

5.2. YOLO Mode

Control whether Claude can make changes without confirmation:

// Development mode - allow changes
ClaudeCodeAgentOptions devOptions = ClaudeCodeAgentOptions.builder()
    .yolo(true)
    .build();

// Analysis mode - read-only
ClaudeCodeAgentOptions analysisOptions = ClaudeCodeAgentOptions.builder()
    .yolo(false)
    .build();

5.3. Timeout Configuration

Set appropriate timeouts for different goal complexities:

// Quick tasks
ClaudeCodeAgentOptions quickOptions = ClaudeCodeAgentOptions.builder()
    .timeout(Duration.ofMinutes(2))
    .build();

// Complex refactoring
ClaudeCodeAgentOptions complexOptions = ClaudeCodeAgentOptions.builder()
    .timeout(Duration.ofMinutes(30))
    .build();

6. Error Handling

6.1. Common Exceptions

try {
    AgentClientResponse response = agentClient.run("Complex refactoring goal");

    if (!response.isSuccessful()) {
        System.err.println("Goal failed: " + response.getResult());
    }

} catch (ClaudeCodeExecutionException e) {
    // Claude CLI process failed
    System.err.println("Claude execution error: " + e.getMessage());

} catch (ClaudeCodeNotFoundException e) {
    // Claude CLI not installed or not in PATH
    System.err.println("Claude CLI not found: " + e.getMessage());

} catch (AgentTimeoutException e) {
    // Goal exceeded configured timeout
    System.err.println("Goal timed out: " + e.getTimeout());

} catch (AgentAuthenticationException e) {
    // Invalid or missing API key
    System.err.println("Authentication failed: " + e.getMessage());
}

6.2. Validation and Recovery

@Service
public class ClaudeCodeService {

    private final AgentClient agentClient;

    public ClaudeCodeService(AgentClient agentClient) {
        this.agentClient = agentClient;
    }

    public String refactorCode(String className, String requirements) {
        // Validate inputs
        if (className == null || className.trim().isEmpty()) {
            throw new IllegalArgumentException("Class name is required");
        }

        try {
            // First, analyze the code
            AgentClientResponse analysis = agentClient
                .goal("Analyze " + className + " and suggest improvements")
                .yolo(false) // Read-only analysis
                .run();

            if (!analysis.isSuccessful()) {
                throw new ServiceException("Analysis failed: " + analysis.getResult());
            }

            // Then perform refactoring
            AgentClientResponse refactoring = agentClient
                .goal("Refactor " + className + " based on: " + requirements)
                .yolo(true) // Allow modifications
                .run();

            return refactoring.getResult();

        } catch (Exception e) {
            // Log error and return meaningful message
            log.error("Refactoring failed for class: {}", className, e);
            throw new ServiceException("Unable to refactor " + className + ": " + e.getMessage());
        }
    }
}

7. Spring Boot Integration

7.1. Auto-Configuration

Create a configuration class for Claude Code:

@Configuration
@ConditionalOnProperty(name = "spring.ai.agent.claude.enabled", havingValue = "true", matchIfMissing = true)
public class ClaudeCodeConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public ClaudeCodeClient claudeCodeClient(@Value("${spring.ai.agent.claude.working-directory:#{systemProperties['user.dir']}}") String workingDir) {
        return ClaudeCodeClient.create(Paths.get(workingDir));
    }

    @Bean
    @ConditionalOnMissingBean
    public ClaudeCodeAgentModel claudeCodeAgentModel(
            ClaudeCodeClient client,
            ClaudeCodeAgentOptions options) {
        return new ClaudeCodeAgentModel(client, options);
    }

    @Bean
    @ConditionalOnMissingBean
    public ClaudeCodeAgentOptions claudeCodeAgentOptions(ClaudeCodeProperties properties) {
        return ClaudeCodeAgentOptions.builder()
            .model(properties.getModel())
            .yolo(properties.isYolo())
            .timeout(properties.getTimeout())
            .maxTokens(properties.getMaxTokens())
            .verbose(properties.isVerbose())
            .build();
    }

    @Bean
    public AgentClient agentClient(ClaudeCodeAgentModel agentModel) {
        return AgentClient.create(agentModel);
    }
}

7.2. Application Properties

Configure Claude Code via application.yml:

spring:
  ai:
    agent:
      claude:
        enabled: true
        model: claude-sonnet-4-0
        working-directory: /path/to/project
        yolo: false
        timeout: PT10M
        max-tokens: 8192
        verbose: true

Or application.properties:

spring.ai.agent.claude.enabled=true
spring.ai.agent.claude.model=claude-sonnet-4-0
spring.ai.agent.claude.working-directory=/path/to/project
spring.ai.agent.claude.yolo=false
spring.ai.agent.claude.timeout=PT10M
spring.ai.agent.claude.max-tokens=8192
spring.ai.agent.claude.verbose=true

8. Best Practices

8.1. Goal Formulation

Write specific, actionable goals for Claude:

// Good: Specific and contextual
agentClient.run("Add input validation to UserController.createUser() method using Bean Validation annotations");

// Good: Clear scope and requirements
agentClient.run("Refactor PaymentService to use the Strategy pattern for different payment processors");

// Avoid: Vague requests
agentClient.run("Fix the code");

// Avoid: Overly broad scope
agentClient.run("Rewrite the entire application");

8.2. Security Considerations

Always be cautious with YOLO mode in production:

@Profile("development")
@Configuration
public class DevelopmentClaudeConfig {

    @Bean
    public ClaudeCodeAgentOptions devClaudeOptions() {
        return ClaudeCodeAgentOptions.builder()
            .yolo(true) // OK for development
            .build();
    }
}

@Profile("production")
@Configuration
public class ProductionClaudeConfig {

    @Bean
    public ClaudeCodeAgentOptions prodClaudeOptions() {
        return ClaudeCodeAgentOptions.builder()
            .yolo(false) // Safe for production
            .build();
    }
}

8.3. Resource Management

Monitor and limit resource usage:

@Component
public class ClaudeCodeMonitor {

    private final MeterRegistry meterRegistry;
    private final AgentClient agentClient;

    public ClaudeCodeMonitor(MeterRegistry meterRegistry, AgentClient agentClient) {
        this.meterRegistry = meterRegistry;
        this.agentClient = agentClient;
    }

    public String executeWithMetrics(String goal) {
        return Timer.Sample.start(meterRegistry)
            .stop(Timer.builder("claude.goal.duration")
                .tag("goal", goal.substring(0, Math.min(goal.length(), 50)))
                .register(meterRegistry))
            .recordCallable(() -> {
                Counter.builder("claude.goal.count").register(meterRegistry).increment();

                AgentClientResponse response = agentClient.run(goal);

                Counter.builder("claude.goal.result")
                    .tag("success", String.valueOf(response.isSuccessful()))
                    .register(meterRegistry)
                    .increment();

                return response.getResult();
            });
    }
}

9. Troubleshooting

9.1. Common Issues

Claude CLI Not Found

Ensure Claude is installed and in your PATH:

# Verify installation
claude --version

# Check PATH
which claude  # macOS/Linux
where claude  # Windows

# Reinstall if needed
npm install -g @anthropic-ai/claude-code

API Key Issues

Verify your API key configuration:

# Check environment variable
echo $ANTHROPIC_API_KEY

# Test with Claude CLI directly
claude --help

Permission Denied

Ensure proper file permissions in working directory:

# Check directory permissions
ls -la /path/to/project

# Fix if needed
chmod -R u+rw /path/to/project

Timeout Issues

Increase timeout for complex tasks:

ClaudeCodeAgentOptions options = ClaudeCodeAgentOptions.builder()
    .timeout(Duration.ofMinutes(30)) // Longer timeout
    .build();

9.2. Debugging

Enable verbose logging to troubleshoot issues:

ClaudeCodeAgentOptions debugOptions = ClaudeCodeAgentOptions.builder()
    .verbose(true)
    .build();

Add logging configuration:

logging:
  level:
    org.springaicommunity.agents.claudecode: DEBUG
    org.springaicommunity.agents.client: DEBUG

10. Next Steps