Creating States with Annotations
Overview
The Claude automator demonstrates the new annotation-based approach for defining states. This significantly simplifies state configuration by eliminating manual registration and boilerplate code.
Working State
The Working state represents the screen where Claude is actively responding:
WorkingState.java
package com.claude.automator.states;
import io.github.jspinak.brobot.annotations.State;
import io.github.jspinak.brobot.model.state.StateImage;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
@State
@Getter
@Slf4j
public class WorkingState {
private final StateImage claudeIcon;
public WorkingState() {
log.info("Creating WorkingState");
// Create the claude icon images
claudeIcon = new StateImage.Builder()
.addPatterns("working/claude-icon-1",
"working/claude-icon-2",
"working/claude-icon-3",
"working/claude-icon-4")
.setName("ClaudeIcon")
.build();
log.info("WorkingState created successfully");
}
}
Key Features:
- @State Annotation: Automatically registers the state with Brobot
- No Manual Registration: No need for StateRegistrationListener
- Direct Component Access: The
claudeIcon
is stored as a field with a getter - Multiple Image Patterns: Uses
addPatterns()
to handle UI variations - Simplified Structure: No need for State.Builder or StateEnum
Prompt State
The Prompt state represents the screen where we can enter prompts:
PromptState.java
package com.claude.automator.states;
import io.github.jspinak.brobot.annotations.State;
import io.github.jspinak.brobot.model.state.StateImage;
import io.github.jspinak.brobot.model.state.StateString;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
@State(initial = true)
@Getter
@Slf4j
public class PromptState {
private final StateImage claudePrompt;
private final StateString continueCommand;
public PromptState() {
log.info("Creating PromptState");
// Initialize the claude prompt image
claudePrompt = new StateImage.Builder()
.addPatterns("prompt/claude-prompt-1",
"prompt/claude-prompt-2",
"prompt/claude-prompt-3")
.setName("ClaudePrompt")
.build();
// Create the continue command as a string
continueCommand = new StateString.Builder()
.setName("ContinueCommand")
.setString("continue\n")
.build();
log.info("PromptState created successfully");
}
}
Key Features:
- Initial State Marking:
@State(initial = true)
designates this as the starting state - Automatic Framework Integration: Spring and Brobot automatically discover and register the state
- Mixed State Components: Combines StateImage (for visual elements) and StateString (for text input)
- Clean API: Direct access to both
claudePrompt
andcontinueCommand
- No Boilerplate: No need for State objects or manual registration
Comparison: Before and After
Before (Manual Registration):
// StateRegistrationListener.java - 67 lines of boilerplate
@Component
@RequiredArgsConstructor
@Slf4j
public class StateRegistrationListener {
private final StateService stateService;
private final StateTransitionStore stateTransitionStore;
// ... lots of manual registration code
@EventListener(ApplicationReadyEvent.class)
public void onApplicationReady() {
stateService.save(workingState.getState());
stateService.save(promptState.getState());
// ... more registration
}
}
After (With Annotations):
// No registration needed! Just add @State annotation
@State(initial = true)
@Getter
@Slf4j
public class PromptState {
// State definition
}
Benefits of Annotation Approach
- Zero Configuration: States are automatically discovered and registered
- Less Code: Eliminate 60+ lines of registration boilerplate
- Clearer Intent:
@State(initial = true)
clearly marks starting states - Better Separation: State definition and registration are unified
- Type Safety: Compile-time checking of state relationships
Best Practices
- Always use @Getter - Lombok generates getters for state components
- Always use @Slf4j - Provides consistent logging
- Mark initial states - Use
@State(initial = true)
for entry points - Keep states focused - Each state represents one UI screen
- Use descriptive names - Component names should be self-documenting
Required Annotations
When using the annotation system, include these annotations on your state classes:
@State // Brobot state registration
@Getter // Lombok getter generation
@Slf4j // Lombok logging
public class MyState {
// State implementation
}
Next Steps
With our states defined using annotations, we'll implement transitions that also use the annotation system for automatic registration and simplified configuration.