Gemini CLI SDK
The Gemini CLI SDK provides Java integration with Google’s Gemini command-line coding agent, bringing Google’s AI coding capabilities to Spring applications.
1. Overview
Gemini CLI is Google’s autonomous coding agent that can understand and modify codebases using Google’s Gemini language models. The Spring AI Gemini integration makes these capabilities accessible from Java applications.
2. Installation
2.1. Prerequisites
-
Install Gemini CLI:
npm install -g @google/generative-ai-cli
-
Set API Key:
export GEMINI_API_KEY="your-api-key-here"
Get your API key from the Google AI Studio.
-
Verify Installation:
gemini --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>
<!-- Gemini CLI integration -->
<dependency>
<groupId>org.springaicommunity.agents</groupId>
<artifactId>spring-ai-gemini</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.gemini.GeminiAgentModel;
import org.springaicommunity.agents.gemini.GeminiAgentOptions;
import org.springaicommunity.agents.gemini.sdk.GeminiClient;
import java.nio.file.Paths;
public class GeminiExample {
public static void main(String[] args) {
// 1. Create the Gemini client
GeminiClient geminiClient = GeminiClient.create(
Paths.get(System.getProperty("user.dir"))
);
// 2. Configure agent options
GeminiAgentOptions options = GeminiAgentOptions.builder()
.model("gemini-1.5-pro")
.yolo(true)
.build();
// 3. Create the agent model
GeminiAgentModel agentModel = new GeminiAgentModel(geminiClient, options);
// 4. Create AgentClient
AgentClient agentClient = AgentClient.create(agentModel);
// 5. Execute a goal
AgentClientResponse response = agentClient.run(
"Create a simple Spring Boot REST controller for managing books"
);
System.out.println("Result: " + response.getResult());
System.out.println("Success: " + response.isSuccessful());
}
}
4. Configuration
4.1. GeminiClient
The GeminiClient
manages communication with the Gemini CLI:
// Create with default working directory
GeminiClient client = GeminiClient.create();
// Create with specific working directory
Path projectPath = Paths.get("/path/to/project");
GeminiClient client = GeminiClient.create(projectPath);
// Create with custom Gemini command path
GeminiClient client = GeminiClient.create(
projectPath,
"/custom/path/to/gemini"
);
4.2. GeminiAgentOptions
Configure Gemini-specific behavior:
GeminiAgentOptions options = GeminiAgentOptions.builder()
// Model selection
.model("gemini-1.5-pro") // or "gemini-1.5-flash"
// 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
// Google-specific options
.temperature(0.3) // Creativity level
.candidateCount(1) // Number of response candidates
.build();
4.3. Model Options
Available Gemini models:
Model | Description | Best For |
---|---|---|
|
Most capable model with 1M token context window |
Large codebases, complex refactoring, architectural changes |
|
Faster model optimized for speed and efficiency |
Quick fixes, simple tasks, rapid iteration |
|
Previous generation model |
Legacy support, specific use cases |
5. Advanced Features
5.1. Working Directory Management
Gemini CLI operates within a specific directory context:
// Configure working directory via client
GeminiClient client = GeminiClient.create(
Paths.get("/path/to/project")
);
// Or via AgentClient fluent API
AgentClientResponse response = agentClient
.goal("Add unit tests to the ProductService")
.workingDirectory("/path/to/project")
.run();
5.2. YOLO Mode
Control whether Gemini can make changes without confirmation:
// Development mode - allow changes
GeminiAgentOptions devOptions = GeminiAgentOptions.builder()
.yolo(true)
.build();
// Analysis mode - read-only
GeminiAgentOptions analysisOptions = GeminiAgentOptions.builder()
.yolo(false)
.build();
5.3. Temperature and Creativity
Control the creativity level of responses:
// Conservative (more deterministic)
GeminiAgentOptions conservativeOptions = GeminiAgentOptions.builder()
.temperature(0.1)
.build();
// Balanced (default)
GeminiAgentOptions balancedOptions = GeminiAgentOptions.builder()
.temperature(0.3)
.build();
// Creative (more diverse)
GeminiAgentOptions creativeOptions = GeminiAgentOptions.builder()
.temperature(0.7)
.build();
5.4. Context Window Optimization
Leverage Gemini’s large context window for complex projects:
GeminiAgentOptions largeContextOptions = GeminiAgentOptions.builder()
.model("gemini-1.5-pro") // 1M token context
.maxTokens(100000) // Large output
.build();
// Handle entire project refactoring
AgentClientResponse response = agentClient
.goal("Refactor this entire Spring Boot application to use reactive programming")
.options(largeContextOptions)
.run();
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 (GeminiExecutionException e) {
// Gemini CLI process failed
System.err.println("Gemini execution error: " + e.getMessage());
} catch (GeminiNotFoundException e) {
// Gemini CLI not installed or not in PATH
System.err.println("Gemini 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());
} catch (GeminiQuotaExceededException e) {
// API quota exceeded
System.err.println("Quota exceeded: " + e.getMessage());
}
6.2. Retry Logic with Exponential Backoff
@Service
public class GeminiServiceWithRetry {
private final AgentClient agentClient;
private final RetryTemplate retryTemplate;
public GeminiServiceWithRetry(AgentClient agentClient) {
this.agentClient = agentClient;
this.retryTemplate = RetryTemplate.builder()
.maxAttempts(3)
.exponentialBackoff(1000, 2, 10000)
.retryOn(GeminiQuotaExceededException.class)
.retryOn(GeminiExecutionException.class)
.build();
}
public String generateCode(String requirements) {
return retryTemplate.execute(context -> {
AgentClientResponse response = agentClient.run(requirements);
if (!response.isSuccessful()) {
throw new GeminiExecutionException("Goal failed: " + response.getResult());
}
return response.getResult();
});
}
}
7. Spring Boot Integration
7.1. Auto-Configuration
Create a configuration class for Gemini:
@Configuration
@ConditionalOnProperty(name = "spring.ai.agent.gemini.enabled", havingValue = "true", matchIfMissing = true)
public class GeminiConfiguration {
@Bean
@ConditionalOnMissingBean
public GeminiClient geminiClient(@Value("${spring.ai.agent.gemini.working-directory:#{systemProperties['user.dir']}}") String workingDir) {
return GeminiClient.create(Paths.get(workingDir));
}
@Bean
@ConditionalOnMissingBean
public GeminiAgentModel geminiAgentModel(
GeminiClient client,
GeminiAgentOptions options) {
return new GeminiAgentModel(client, options);
}
@Bean
@ConditionalOnMissingBean
public GeminiAgentOptions geminiAgentOptions(GeminiProperties properties) {
return GeminiAgentOptions.builder()
.model(properties.getModel())
.yolo(properties.isYolo())
.timeout(properties.getTimeout())
.maxTokens(properties.getMaxTokens())
.temperature(properties.getTemperature())
.verbose(properties.isVerbose())
.build();
}
@Bean
public AgentClient agentClient(GeminiAgentModel agentModel) {
return AgentClient.create(agentModel);
}
}
7.2. Application Properties
Configure Gemini via application.yml
:
spring:
ai:
agent:
gemini:
enabled: true
model: gemini-1.5-pro
working-directory: /path/to/project
yolo: false
timeout: PT10M
max-tokens: 8192
temperature: 0.3
verbose: true
Or application.properties
:
spring.ai.agent.gemini.enabled=true
spring.ai.agent.gemini.model=gemini-1.5-pro
spring.ai.agent.gemini.working-directory=/path/to/project
spring.ai.agent.gemini.yolo=false
spring.ai.agent.gemini.timeout=PT10M
spring.ai.agent.gemini.max-tokens=8192
spring.ai.agent.gemini.temperature=0.3
spring.ai.agent.gemini.verbose=true
8. Google Cloud Integration
8.1. Service Account Authentication
For production deployments using Google Cloud:
spring:
ai:
agent:
gemini:
authentication:
type: service-account
service-account-file: /path/to/service-account.json
project-id: your-gcp-project-id
@Configuration
@ConditionalOnProperty(name = "spring.ai.agent.gemini.authentication.type", havingValue = "service-account")
public class GeminiCloudConfiguration {
@Bean
public GoogleCredentials geminiCredentials(
@Value("${spring.ai.agent.gemini.authentication.service-account-file}") String serviceAccountFile)
throws IOException {
return ServiceAccountCredentials.fromStream(
new FileInputStream(serviceAccountFile)
);
}
@Bean
public GeminiClient geminiCloudClient(GoogleCredentials credentials) {
return GeminiClient.builder()
.credentials(credentials)
.build();
}
}
9. Best Practices
9.1. Goal Formulation for Google AI
Leverage Gemini’s strengths in understanding context and patterns:
// Good: Leverage Google's pattern recognition
agentClient.run("Apply Google's Java style guide to this codebase and fix all violations");
// Good: Use Gemini's architectural understanding
agentClient.run("Convert this monolithic application to microservices following Google Cloud best practices");
// Good: Leverage large context window
agentClient.run("Analyze this entire codebase and identify all security vulnerabilities");
9.2. Model Selection Strategy
Choose models based on goal complexity:
@Service
public class GeminiTaskRouter {
public String executeGoal(String goal, GoalComplexity complexity) {
GeminiAgentOptions options = switch (complexity) {
case SIMPLE -> GeminiAgentOptions.builder()
.model("gemini-1.5-flash") // Fast for simple tasks
.temperature(0.1)
.build();
case MODERATE -> GeminiAgentOptions.builder()
.model("gemini-1.5-pro") // Balanced
.temperature(0.3)
.build();
case COMPLEX -> GeminiAgentOptions.builder()
.model("gemini-1.5-pro") // Full power for complex tasks
.temperature(0.1) // Conservative for accuracy
.maxTokens(50000) // Large output
.timeout(Duration.ofMinutes(30))
.build();
};
return agentClient.goal(goal).options(options).run().getResult();
}
}
9.3. Quota Management
Monitor and manage API quotas:
@Component
public class GeminiQuotaManager {
private final AtomicInteger requestCount = new AtomicInteger(0);
private final AtomicLong lastResetTime = new AtomicLong(System.currentTimeMillis());
@Value("${spring.ai.agent.gemini.quota.requests-per-minute:60}")
private int requestsPerMinute;
public boolean canMakeRequest() {
long currentTime = System.currentTimeMillis();
long timeSinceReset = currentTime - lastResetTime.get();
// Reset counter every minute
if (timeSinceReset > 60000) {
requestCount.set(0);
lastResetTime.set(currentTime);
}
return requestCount.get() < requestsPerMinute;
}
public void recordRequest() {
requestCount.incrementAndGet();
}
}
10. Monitoring and Observability
10.1. Metrics Collection
@Component
public class GeminiMetrics {
private final MeterRegistry meterRegistry;
private final Counter requestCounter;
private final Timer requestTimer;
private final Gauge quotaGauge;
public GeminiMetrics(MeterRegistry meterRegistry, GeminiQuotaManager quotaManager) {
this.meterRegistry = meterRegistry;
this.requestCounter = Counter.builder("gemini.requests.total")
.tag("provider", "gemini")
.register(meterRegistry);
this.requestTimer = Timer.builder("gemini.request.duration")
.register(meterRegistry);
this.quotaGauge = Gauge.builder("gemini.quota.remaining")
.register(meterRegistry, quotaManager, GeminiQuotaManager::getRemainingRequests);
}
public AgentClientResponse executeWithMetrics(String goal) {
return Timer.Sample.start(meterRegistry)
.stop(requestTimer)
.recordCallable(() -> {
requestCounter.increment();
return agentClient.run(goal);
});
}
}
11. Troubleshooting
11.1. Common Issues
Gemini CLI Not Found
# Verify installation
gemini --version
# Check PATH
which gemini # macOS/Linux
where gemini # Windows
# Reinstall if needed
npm install -g @google/generative-ai-cli
API Key Issues
# Check environment variable
echo $GEMINI_API_KEY
# Test with Gemini CLI directly
gemini --help
Quota Exceeded
Monitor your usage in Google AI Studio and implement quota management:
@Component
public class GeminiHealthIndicator implements HealthIndicator {
private final GeminiQuotaManager quotaManager;
@Override
public Health health() {
if (quotaManager.canMakeRequest()) {
return Health.up()
.withDetail("quota", "Available")
.withDetail("remaining", quotaManager.getRemainingRequests())
.build();
} else {
return Health.down()
.withDetail("quota", "Exceeded")
.withDetail("resetTime", quotaManager.getNextResetTime())
.build();
}
}
}
12. Comparison with Claude Code
While both are autonomous coding agents, they have different strengths:
Feature | Gemini CLI | Claude Code |
---|---|---|
Context Window |
1M tokens (gemini-1.5-pro) |
~200K tokens |
Speed |
Very fast with gemini-1.5-flash |
Consistent performance |
Integration |
Google Cloud ecosystem |
Anthropic ecosystem |
Best For |
Large codebases, Google Cloud |
General development, detailed reasoning |
13. Next Steps
-
Compare different agent providers in Claude Code SDK
-
Learn the unified API in AgentClient API
-
See practical examples in Sample Agents