
Spring Boot Scanner
- 1 installs
- 21 repo stars
- Updated August 5, 2026
- joaquimscosta/arkhe-claude-plugins
Detects Spring Boot patterns in Java/Kotlin code and routes to the appropriate Spring Boot skill, auto-invoking for low-risk patterns.
About
Scans Spring Boot Java or Kotlin code to detect annotations and patterns and routes to the relevant Spring Boot skill. A developer relies on it to auto-load the right web-api, data, security, or testing guidance while editing.
- Annotation-based pattern detection and skill routing
- Progressive automation: auto for low-risk, confirm for high-risk
Spring Boot Scanner by the numbers
- 1 all-time installs (skills.sh)
- Ranked #79 of 89 Java & JVM skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/joaquimscosta/arkhe-claude-plugins --skill spring-boot-scannerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 21 |
| Last updated | August 5, 2026 |
| Repository | joaquimscosta/arkhe-claude-plugins ↗ |
What it does
Detects Spring Boot patterns in Java/Kotlin code and routes to the appropriate Spring Boot skill, auto-invoking for low-risk patterns.
Files
Spring Boot Scanner
Smart pattern detection and skill routing for Spring Boot projects.
Core Behavior
Trigger Conditions:
- Editing
*.javaor*.ktfiles in a project withspring-boot-starterdependencies - Working with
pom.xmlorbuild.gradle*containing Spring Boot - User mentions "Spring Boot", "Spring Security", "Spring Data", etc.
Action: Scan code → Detect patterns → Route to appropriate skill
Detection Algorithm
Scans in 3 phases: (1) detect Spring Boot project via build files, (2) scan annotations against the map below, (3) route by risk level — LOW auto-invokes, HIGH confirms first. See WORKFLOW.md for the full step-by-step detection flow.
Annotation → Skill Map
| Annotation Pattern | Detected Skill | Risk Level |
|---|---|---|
@RestController, @GetMapping, @PostMapping, @RequestMapping | spring-boot-web-api | LOW |
@Entity, @Repository, @Aggregate, @MappedSuperclass | spring-boot-data-ddd | LOW |
@Service in **/domain/** or **/service/** | domain-driven-design | LOW |
@ApplicationModule, @ApplicationModuleListener | spring-boot-modulith | LOW |
@Timed, @Counted, HealthIndicator, MeterRegistry | spring-boot-observability | LOW |
@EnableWebSecurity, @PreAuthorize, @Secured, SecurityFilterChain | spring-boot-security | HIGH |
@SpringBootTest, @WebMvcTest, @DataJpaTest, @MockitoBean | spring-boot-testing | HIGH |
@MockBean (deprecated) | spring-boot-testing | HIGH + WARNING |
| Build file with version < 4.0 | spring-boot-verify | HIGH |
Use this script to detect patterns:
# Run from project root
python3 scripts/detect_patterns.py /path/to/file.javaOr use Grep directly:
# Web API detection
grep -l "@RestController\|@GetMapping\|@PostMapping" **/*.java
# Security detection
grep -l "@EnableWebSecurity\|@PreAuthorize\|SecurityFilterChain" **/*.java
# Testing detection
grep -l "@SpringBootTest\|@WebMvcTest\|@MockitoBean\|@MockBean" **/*.javaEscalation Triggers
Always confirm before proceeding when detecting:
| Pattern | Reason | Action |
|---|---|---|
@EnableGlobalMethodSecurity | Deprecated in Security 6+ | Confirm + Migration guidance |
@MockBean | Deprecated in Boot 3.4+ | Confirm + Show @MockitoBean |
spring-boot-starter-parent < 3.0 | Major migration needed | Confirm + Suggest verify-upgrade |
.and() in security config | Removed in Security 7 | Confirm + Lambda DSL guidance |
com.fasterxml.jackson | Jackson 3 migration | Confirm + Namespace change |
Integration with Existing Components
Delegates to Skills:
spring-boot-web-api→ REST patternsspring-boot-data-ddd→ Repository/Entity patternsspring-boot-security→ Security configurationspring-boot-testing→ Test patternsspring-boot-modulith→ Module structurespring-boot-observability→ Metrics/Healthspring-boot-verify→ Dependencies/Configdomain-driven-design→ DDD architecture
Delegates to Agents (for comprehensive review):
spring-boot-reviewer→ Full codebase reviewspring-boot-upgrade-verifier→ Migration analysis
When to delegate to agents:
- User asks for "review" or "scan" of entire project
- Multiple HIGH RISK patterns across many files
- Explicit
/spring-reviewor/verify-upgradecommand
Known Limitations
- Annotation-based only: Detects standard Spring annotations, not custom/meta-annotations or XML configuration
- Java and Kotlin only: Scans
*.javaand*.ktfiles; no Groovy/Scala support - Spring Boot 3.x+ optimized: Escalation patterns focus on Boot 3.x → 4.x migration; older versions may have gaps
- No AST parsing: Uses regex matching, so patterns in comments/strings may cause false positives
Escape Hatch
If scanner guidance isn't helpful for the current context:
| Scenario | Action |
|---|---|
| Skip LOW RISK guidance | Ignore suggestions and continue working |
| Skip HIGH RISK confirmation | Select "Continue without guidance" option |
| Need comprehensive review | Use /spring-review command instead |
| Disable temporarily | Remove spring-boot-scanner from active skills |
The scanner is advisory—it suggests skills but never blocks the workflow.
Related Skills
| Need | Skill |
|---|---|
| DDD concepts | domain-driven-design |
| Data layer | spring-boot-data-ddd |
| REST APIs | spring-boot-web-api |
| Security config | spring-boot-security |
| Full codebase review | Use /spring-review command |
Detailed References
- Workflow: See WORKFLOW.md for step-by-step detection flow
- Examples: See EXAMPLES.md for trigger scenarios
- Troubleshooting: See TROUBLESHOOTING.md for common issues
- Detection Script: See scripts/detect_patterns.py for programmatic detection
Critical Reminders
1. Always check project type first — Only activate for Spring Boot projects 2. Respect risk levels — Never auto-invoke security/testing/verify without confirmation 3. Batch notifications — Don't spam user with multiple skill suggestions 4. Delegate to agents for scale — Use reviewer agent for multi-file analysis 5. Preserve user flow — Guidance should assist, not interrupt
Spring Boot Scanner Examples
Real-world scenarios showing how the scanner detects and routes.
Example 1: Controller File (Low Risk - Auto-Invoke)
User Action: Editing UserController.java
File Content:
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
public ResponseEntity<UserDto> getUser(@PathVariable Long id) {
// ...
}
@PostMapping
public ResponseEntity<UserDto> createUser(@Valid @RequestBody CreateUserRequest request) {
// ...
}
}Scanner Detection:
Detected annotations: @RestController, @GetMapping, @PostMapping, @RequestMapping
Skill match: spring-boot-web-api
Risk level: LOWScanner Response:
I notice you're working with REST controller patterns. Here's guidance from spring-boot-web-api:
**Request/Response Best Practices:**
- Use DTOs instead of entities in API responses
- Apply `@Valid` for request body validation
- Return `ResponseEntity<T>` for explicit status codes
**Error Handling:**
- Use `ProblemDetail` (RFC 9457) for error responses
- Define `@ExceptionHandler` in `@ControllerAdvice`
See spring-boot-web-api skill for detailed patterns and examples.---
Example 2: Security Configuration (High Risk - Confirm)
User Action: Creating SecurityConfig.java
File Content:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
}Scanner Detection:
Detected annotations: @EnableWebSecurity, SecurityFilterChain
Skill match: spring-boot-security
Risk level: HIGHScanner Response:
I detected security configuration patterns. This involves authentication and authorization setup.
[AskUserQuestion]
Question: "Would you like security guidance for this configuration?"
Options:
1. "Load spring-boot-security skill" - Full Lambda DSL patterns, JWT/OAuth2 setup
2. "Quick validation only" - Check for common security issues
3. "Continue without guidance" - I understand security configIf User Selects Option 1:
Loading spring-boot-security skill...
**Spring Security 7 Requirements:**
- ✅ Using Lambda DSL (correct)
- ✅ Using `requestMatchers()` (correct)
- ✅ Using `authorizeHttpRequests()` (correct)
**Recommendations:**
- Consider adding CSRF protection for state-changing endpoints
- Add method security with `@PreAuthorize` for fine-grained access
See EXAMPLES.md in spring-boot-security for complete patterns.---
Example 3: Deprecated Pattern (Escalation)
User Action: Opening legacy TestConfig.java
File Content:
@SpringBootTest
public class UserServiceTest {
@MockBean // Deprecated in Boot 3.4+
private UserRepository userRepository;
@Test
void shouldCreateUser() {
// ...
}
}Scanner Detection:
Detected annotations: @SpringBootTest, @MockBean
Skill match: spring-boot-testing
Risk level: HIGH
Escalation: @MockBean is deprecatedScanner Response:
⚠️ **Deprecated Pattern Detected**
Found `@MockBean` which is deprecated since Spring Boot 3.4. Use `@MockitoBean` instead.
**Migration:**// Before (deprecated) @MockBean private UserRepository userRepository;
// After (Spring Boot 4.x) @MockitoBean private UserRepository userRepository;
**Note:** `@MockitoBean` requires import from `org.springframework.test.context.bean.override.mockito`
Would you like me to help migrate this test file?
[AskUserQuestion]
Options:
1. "Migrate all @MockBean usages" - Find and replace in this file
2. "Scan project for @MockBean" - Check all test files
3. "Load spring-boot-testing skill" - Full testing patterns---
Example 4: Entity with Repository (Low Risk - Batched)
User Action: Creating Order.java and OrderRepository.java
Order.java:
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "customer_id")
private Customer customer;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> items = new ArrayList<>();
}OrderRepository.java:
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByCustomerId(Long customerId);
@Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.id = :id")
Optional<Order> findByIdWithItems(@Param("id") Long id);
}Scanner Detection:
Detected annotations: @Entity, @Repository, @ManyToOne, @OneToMany
Skill matches: spring-boot-data-ddd, domain-driven-design
Risk level: LOW (both)Scanner Response:
I notice you're working with JPA entities and repositories. Here's combined guidance:
**From spring-boot-data-ddd:**
- Use `JOIN FETCH` to avoid N+1 queries (you're doing this ✓)
- Consider `@EntityGraph` for reusable fetch strategies
- Use `orphanRemoval = true` for owned collections (you're doing this ✓)
**From domain-driven-design:**
- Consider if Order is an Aggregate Root
- OrderItems should be Value Objects if they have no independent identity
- Customer reference suggests a different Aggregate - use ID reference instead
**Potential improvement:**// Instead of entity reference (crosses aggregate boundary) @ManyToOne private Customer customer;
// Use ID reference (respects aggregate boundaries) @Column(name = "customer_id") private Long customerId;
Would you like more details on DDD aggregate patterns?---
Example 5: Mixed Patterns (Low + High Risk)
User Action: Creating integration test with security
File Content:
@SpringBootTest
@AutoConfigureMockMvc
public class UserApiIntegrationTest {
@Autowired
private MockMvc mockMvc;
@MockitoBean
private UserService userService;
@Test
@WithMockUser(roles = "ADMIN")
void adminCanDeleteUser() throws Exception {
mockMvc.perform(delete("/api/users/1"))
.andExpect(status().isNoContent());
}
}Scanner Detection:
Detected annotations:
- @SpringBootTest, @MockitoBean → spring-boot-testing (HIGH)
- @WithMockUser → spring-boot-security (HIGH)
- MockMvc patterns → spring-boot-web-api (LOW)Scanner Response:
I detected multiple patterns in your integration test:
**Auto-loaded (web-api):**
- MockMvc patterns detected - use `contentType(APPLICATION_JSON)` for JSON requests
**Confirmation needed:**
This test involves security testing patterns (@WithMockUser) and slice testing (@SpringBootTest).
[AskUserQuestion]
Question: "Which guidance would you like for this test?"
Options:
1. "Both security + testing skills" - Comprehensive test patterns
2. "Security testing only" - Focus on @WithMockUser, JWT mocking
3. "Integration testing only" - @SpringBootTest, MockMvc patterns
4. "Continue without guidance"---
Example 6: Build File (Verify Trigger)
User Action: Opening pom.xml
File Content:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>Scanner Detection:
Spring Boot version: 3.2.1 (< 4.0)
Detected: com.fasterxml.jackson (Jackson 2.x)
Skill match: spring-boot-verify
Risk level: HIGH
Escalations:
- Version < 4.0 (migration opportunity)
- Jackson 2.x namespace (will change in Boot 4)Scanner Response:
I analyzed your Spring Boot project configuration:
**Current State:**
- Spring Boot version: 3.2.1
- Jackson: 2.x (com.fasterxml namespace)
⚠️ **Migration Considerations:**
Spring Boot 4.0 introduces breaking changes:
| Current | Spring Boot 4.0 |
|---------|-----------------|
| `spring-boot-starter-web` | `spring-boot-starter-webmvc` |
| `com.fasterxml.jackson` | `tools.jackson` |
| Java 17+ | Java 21+ recommended |
[AskUserQuestion]
Question: "Would you like migration analysis?"
Options:
1. "Run full upgrade verification" - Launch verify-upgrade agent
2. "Load spring-boot-verify skill" - Dependency guidance only
3. "Not planning to upgrade yet" - Continue as-is---
Example 7: Comprehensive Review Request
User Action: "Can you review my Spring Boot project for best practices?"
Scanner Response:
For a comprehensive review, I'll delegate to the spring-boot-reviewer agent which can:
1. **Discover** - Scan all Java files, detect which skills are relevant
2. **Parallel Review** - Launch specialized reviewers for each detected area
3. **Report** - Consolidate findings with severity levels
[Agent tool invocation]
Launching spring-boot-reviewer agent with scope: "all"
The reviewer will check:
- ✓ Web API patterns (if controllers found)
- ✓ Data/Repository patterns (if entities found)
- ✓ Security configuration (if security files found)
- ✓ Testing patterns (if tests found)
- ✓ Dependency versions (always checked)
Review in progress...---
Quick Reference: Trigger → Response
| Trigger | Risk | Response |
|---|---|---|
| @RestController | LOW | Auto-invoke web-api guidance |
| @Entity | LOW | Auto-invoke data-ddd guidance |
| @Service in domain/** | LOW | Auto-invoke DDD guidance |
| @EnableWebSecurity | HIGH | Ask before loading security |
| @SpringBootTest | HIGH | Ask before loading testing |
| @MockBean | HIGH + WARN | Show deprecation + ask |
| pom.xml < 4.0 | HIGH | Ask about migration |
| "review my project" | DELEGATE | Launch reviewer agent |
#!/usr/bin/env python3
"""
Spring Boot Pattern Detector
Scans Java and Kotlin files for Spring Boot annotations and returns skill recommendations.
Uses only standard library (no external dependencies).
Usage:
python3 detect_patterns.py <file_path>
python3 detect_patterns.py <directory_path> --recursive
Output:
JSON with detected patterns, skill mappings, and risk levels.
"""
import json
import re
import sys
from pathlib import Path
from typing import Dict, List, Set, Tuple
# Annotation patterns mapped to skills
SKILL_PATTERNS: Dict[str, List[str]] = {
"spring-boot-web-api": [
r"@RestController",
r"@Controller",
r"@GetMapping",
r"@PostMapping",
r"@PutMapping",
r"@DeleteMapping",
r"@PatchMapping",
r"@RequestMapping",
r"@ResponseBody",
r"@RequestBody",
r"@PathVariable",
r"@RequestParam",
r"@ExceptionHandler",
r"@ControllerAdvice",
r"@RestControllerAdvice",
],
"spring-boot-data-ddd": [
r"@Entity",
r"@Repository",
r"@MappedSuperclass",
r"@Embeddable",
r"@EmbeddedId",
r"@OneToMany",
r"@ManyToOne",
r"@ManyToMany",
r"@OneToOne",
r"@JoinColumn",
r"@JoinTable",
r"@Query",
r"@Modifying",
r"@EntityGraph",
r"JpaRepository",
r"CrudRepository",
r"ListCrudRepository",
r"ListPagingAndSortingRepository",
r"PagingAndSortingRepository",
],
"spring-boot-security": [
r"@EnableWebSecurity",
r"@EnableMethodSecurity",
r"@PreAuthorize",
r"@PostAuthorize",
r"@Secured",
r"@RolesAllowed",
r"SecurityFilterChain",
r"AuthenticationManager",
r"UserDetailsService",
r"PasswordEncoder",
r"JwtDecoder",
r"OAuth2ResourceServer",
],
"spring-boot-testing": [
r"@SpringBootTest",
r"@WebMvcTest",
r"@DataJpaTest",
r"@DataJdbcTest",
r"@JsonTest",
r"@WebFluxTest",
r"@MockitoBean",
r"@SpyBean",
r"@ServiceConnection",
r"@Testcontainers",
r"@Container",
r"ApplicationModuleTest",
],
"spring-boot-modulith": [
r"@ApplicationModule",
r"@ApplicationModuleListener",
r"@NamedInterface",
r"@Externalized",
r"ApplicationModuleTest",
r"Scenario",
],
"spring-boot-observability": [
r"@Timed",
r"@Counted",
r"@Observed",
r"HealthIndicator",
r"MeterRegistry",
r"Tracer",
r"Span",
r"ObservationRegistry",
r"@Endpoint",
r"@ReadOperation",
r"@WriteOperation",
],
"domain-driven-design": [
r"@DomainService",
r"@ValueObject",
r"@AggregateRoot",
r"@Aggregate",
r"@DomainEvent",
r"AbstractAggregateRoot",
],
}
# Deprecated/escalation patterns
ESCALATION_PATTERNS: Dict[str, Dict] = {
"@MockBean": {
"reason": "Deprecated since Spring Boot 3.4",
"replacement": "@MockitoBean",
"severity": "WARNING",
},
"@EnableGlobalMethodSecurity": {
"reason": "Deprecated, use @EnableMethodSecurity",
"replacement": "@EnableMethodSecurity",
"severity": "WARNING",
},
r"\.and\(\)": {
"reason": "Removed in Spring Security 7",
"replacement": "Use Lambda DSL closures",
"severity": "ERROR",
},
"antMatchers": {
"reason": "Removed in Spring Security 6",
"replacement": "requestMatchers()",
"severity": "ERROR",
},
"authorizeRequests": {
"reason": "Deprecated in Spring Security 6",
"replacement": "authorizeHttpRequests()",
"severity": "WARNING",
},
r"com\.fasterxml\.jackson": {
"reason": "Namespace changes in Jackson 3 (Spring Boot 4)",
"replacement": "tools.jackson",
"severity": "INFO",
},
"WebSecurityConfigurerAdapter": {
"reason": "Removed in Spring Security 5.7, completely gone in Spring Boot 4",
"replacement": "SecurityFilterChain @Bean method",
"severity": "ERROR",
},
r"javax\.(persistence|servlet|validation|inject|annotation)": {
"reason": "javax.* namespace removed in Spring Boot 3+",
"replacement": "jakarta.* namespace (jakarta.persistence, jakarta.servlet, etc.)",
"severity": "ERROR",
},
r"import\s+javax\.": {
"reason": "javax.* imports must migrate to jakarta.*",
"replacement": "Change import statements from javax.* to jakarta.*",
"severity": "ERROR",
},
}
# Risk classification
LOW_RISK_SKILLS = {
"spring-boot-web-api",
"spring-boot-data-ddd",
"domain-driven-design",
"spring-boot-modulith",
"spring-boot-observability",
}
HIGH_RISK_SKILLS = {
"spring-boot-security",
"spring-boot-testing",
"spring-boot-verify",
}
def scan_file(file_path: Path) -> Dict:
"""Scan a single file for patterns."""
try:
content = file_path.read_text(encoding="utf-8")
except Exception as e:
return {"error": f"Could not read file: {e}"}
result = {
"file": str(file_path),
"detected_skills": [],
"detected_patterns": {},
"escalations": [],
"risk_classification": {"low_risk": [], "high_risk": []},
}
# Scan for skill patterns
for skill, patterns in SKILL_PATTERNS.items():
matched_patterns = []
for pattern in patterns:
if re.search(pattern, content):
matched_patterns.append(pattern.replace("\\", ""))
if matched_patterns:
result["detected_skills"].append(skill)
result["detected_patterns"][skill] = matched_patterns
# Classify risk
if skill in LOW_RISK_SKILLS:
result["risk_classification"]["low_risk"].append(skill)
elif skill in HIGH_RISK_SKILLS:
result["risk_classification"]["high_risk"].append(skill)
# Scan for escalation patterns
for pattern, info in ESCALATION_PATTERNS.items():
if re.search(pattern, content):
result["escalations"].append(
{
"pattern": pattern.replace("\\", ""),
"reason": info["reason"],
"replacement": info["replacement"],
"severity": info["severity"],
}
)
return result
def scan_directory(dir_path: Path, recursive: bool = True) -> Dict:
"""Scan a directory for Java and Kotlin files."""
results = {
"directory": str(dir_path),
"files_scanned": 0,
"files_with_patterns": [],
"skill_summary": {},
"escalation_summary": [],
"routing_recommendation": {},
}
# Find all Java files
java_pattern = "**/*.java" if recursive else "*.java"
java_files = list(dir_path.glob(java_pattern))
# Find all Kotlin files
kotlin_pattern = "**/*.kt" if recursive else "*.kt"
kotlin_files = list(dir_path.glob(kotlin_pattern))
# Combine Java and Kotlin files
all_files = java_files + kotlin_files
results["files_scanned"] = len(all_files)
all_skills: Set[str] = set()
all_escalations: List[Dict] = []
files_by_skill: Dict[str, List[str]] = {}
for source_file in all_files:
file_result = scan_file(source_file)
if file_result.get("detected_skills"):
results["files_with_patterns"].append(
{
"file": str(source_file),
"skills": file_result["detected_skills"],
"escalations": file_result.get("escalations", []),
}
)
for skill in file_result["detected_skills"]:
all_skills.add(skill)
if skill not in files_by_skill:
files_by_skill[skill] = []
files_by_skill[skill].append(str(source_file))
if file_result.get("escalations"):
all_escalations.extend(file_result["escalations"])
# Build summary
results["skill_summary"] = {
"detected": list(all_skills),
"files_by_skill": files_by_skill,
"low_risk": [s for s in all_skills if s in LOW_RISK_SKILLS],
"high_risk": [s for s in all_skills if s in HIGH_RISK_SKILLS],
}
# Deduplicate escalations
seen_patterns = set()
unique_escalations = []
for esc in all_escalations:
if esc["pattern"] not in seen_patterns:
seen_patterns.add(esc["pattern"])
unique_escalations.append(esc)
results["escalation_summary"] = unique_escalations
# Generate routing recommendation
results["routing_recommendation"] = generate_routing(
results["skill_summary"], results["escalation_summary"]
)
return results
def generate_routing(skill_summary: Dict, escalations: List) -> Dict:
"""Generate routing recommendation based on detected patterns."""
routing = {
"auto_invoke": [],
"require_confirmation": [],
"warnings": [],
"delegate_to_agent": False,
"recommended_action": "",
}
low_risk = skill_summary.get("low_risk", [])
high_risk = skill_summary.get("high_risk", [])
routing["auto_invoke"] = low_risk
routing["require_confirmation"] = high_risk
# Add warnings for escalations
for esc in escalations:
routing["warnings"].append(
f"{esc['severity']}: {esc['pattern']} - {esc['reason']}. Use {esc['replacement']}"
)
# Determine if agent delegation is needed
total_files = len(skill_summary.get("files_by_skill", {}).values())
if total_files > 10 or len(high_risk) > 2:
routing["delegate_to_agent"] = True
routing["recommended_action"] = (
"Delegate to spring-boot-reviewer agent for comprehensive analysis"
)
elif high_risk:
routing["recommended_action"] = (
f"Request confirmation before loading: {', '.join(high_risk)}"
)
elif low_risk:
routing["recommended_action"] = (
f"Auto-invoke guidance for: {', '.join(low_risk)}"
)
else:
routing["recommended_action"] = "No Spring Boot patterns detected"
return routing
def check_spring_boot_project(dir_path: Path) -> Dict:
"""Check if directory is a Spring Boot project."""
result = {"is_spring_boot": False, "build_system": None, "spring_boot_version": None}
# Check for pom.xml
pom_file = dir_path / "pom.xml"
if pom_file.exists():
content = pom_file.read_text(encoding="utf-8")
if "spring-boot-starter" in content or "org.springframework.boot" in content:
result["is_spring_boot"] = True
result["build_system"] = "maven"
# Try to extract version
version_match = re.search(
r"<artifactId>spring-boot-starter-parent</artifactId>\s*<version>([^<]+)</version>",
content,
)
if version_match:
result["spring_boot_version"] = version_match.group(1)
# Check for build.gradle
for gradle_file in ["build.gradle", "build.gradle.kts"]:
gradle_path = dir_path / gradle_file
if gradle_path.exists():
content = gradle_path.read_text(encoding="utf-8")
if "spring-boot" in content.lower():
result["is_spring_boot"] = True
result["build_system"] = "gradle"
# Try to extract version
version_match = re.search(
r"org\.springframework\.boot['\"]?\s*version\s*['\"]?([^'\"]+)",
content,
)
if version_match:
result["spring_boot_version"] = version_match.group(1)
return result
def main():
"""Main entry point."""
if len(sys.argv) < 2:
print("Usage: python3 detect_patterns.py <file_or_directory> [--recursive]")
sys.exit(1)
target = Path(sys.argv[1])
recursive = "--recursive" in sys.argv or "-r" in sys.argv
if not target.exists():
print(json.dumps({"error": f"Path does not exist: {target}"}))
sys.exit(1)
if target.is_file():
result = scan_file(target)
else:
# Check if it's a Spring Boot project first
project_check = check_spring_boot_project(target)
result = scan_directory(target, recursive)
result["project_info"] = project_check
print(json.dumps(result, indent=2))
if __name__ == "__main__":
main()
Spring Boot Scanner Troubleshooting
Common issues encountered during pattern detection and skill routing.
Table of Contents
- No Patterns Detected
- Project Not Recognized
- Annotation Detection Issues
- Script Execution Issues
- False Positives and Negatives
---
No Patterns Detected
Issue: "No Spring Boot patterns detected" for a Spring Boot project
Symptom: Scanner runs but reports no patterns in files that clearly use Spring annotations.
Causes:
- File extensions not recognized (e.g.,
.ktKotlin files) - Annotations using full package names instead of imports
- Non-standard directory structure
- Files excluded by scanning scope
Solution:
1. Verify file extensions: Scanner looks for *.java and *.kt files:
# Check if your files have correct extensions
ls -la src/**/*.java src/**/*.kt 2>/dev/null2. Check annotation format: Scanner looks for @AnnotationName, not fully qualified:
// ✅ Detected
@RestController
public class MyController {}
// ❌ NOT Detected (full package name)
@org.springframework.web.bind.annotation.RestController
public class MyController {}3. Run script directly for debugging:
python3 scripts/detect_patterns.py src/main/java/com/example/MyController.java---
Issue: Patterns detected in some files but not others
Symptom: Scanner detects patterns in some files but misses others.
Causes:
- Non-recursive scan mode
- Files in unexpected locations
- Character encoding issues
Solution:
1. Use recursive scanning:
python3 scripts/detect_patterns.py . --recursive2. Check file encoding (should be UTF-8):
file -i src/main/java/com/example/MyController.java3. Verify file permissions:
ls -la src/main/java/com/example/MyController.java---
Project Not Recognized
Issue: "Not a Spring Boot project" for valid project
Symptom: Scanner exits early claiming project isn't Spring Boot.
Causes:
pom.xmlorbuild.gradlenot in expected location- Non-standard dependency declaration
- Multi-module project structure
Solution:
1. Check build file location:
# Find all Maven projects
find . -name "pom.xml" -type f
# Find all Gradle projects
find . -name "build.gradle*" -type f2. Verify Spring Boot dependency exists:
# Maven
grep -l "spring-boot-starter" **/pom.xml
# Gradle
grep -l "spring-boot\|org.springframework.boot" **/build.gradle*3. For multi-module projects, run from the correct module:
python3 scripts/detect_patterns.py ./backend --recursive---
Issue: Build file detected but version not parsed
Symptom: Project recognized but version shows as null.
Causes:
- Version defined in parent POM
- Version in Gradle version catalog
- Version in gradle.properties
Solution:
Check alternative version locations:
Maven - parent or properties:
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.1</version>
</parent>Gradle - version catalog (gradle/libs.versions.toml):
[versions]
spring-boot = "4.0.1"---
Annotation Detection Issues
Issue: Custom/meta-annotations not detected
Symptom: Files with custom annotations (like @ApiController) not detected.
Cause: Scanner only detects standard Spring annotations.
Solution:
This is a known limitation. For custom annotations:
1. Search for the custom annotation definition to understand what it composes:
grep -r "@interface ApiController" src/2. Use grep directly for custom patterns:
grep -l "@ApiController" **/*.java **/*.kt3. Add patterns to detect_patterns.py if needed for your project.
---
Issue: Annotations in comments detected as false positives
Symptom: Scanner reports patterns from commented-out code.
Cause: Simple regex matching includes comments.
Solution:
Review flagged files manually:
# Check context of detected pattern
grep -n "@RestController" src/main/java/com/example/MyController.javaThe scanner intentionally errs on the side of detection—better to suggest a skill that may not be needed than miss one that is.
---
Script Execution Issues
Issue: "Permission denied" when running script
Symptom: bash: permission denied error.
Solution:
chmod +x scripts/detect_patterns.py---
Issue: "python3: command not found"
Symptom: Python not available in path.
Solution:
1. Check Python installation:
which python3
python3 --version # Requires 3.8+2. Try alternative Python commands:
python scripts/detect_patterns.py .
# or
/usr/bin/python3 scripts/detect_patterns.py .---
Issue: UnicodeDecodeError when scanning files
Symptom: Script crashes with encoding error.
Cause: File contains non-UTF-8 characters.
Solution:
1. Identify problematic file:
find . -name "*.java" -exec file {} \; | grep -v UTF-82. Convert to UTF-8 if needed:
iconv -f ISO-8859-1 -t UTF-8 file.java > file_utf8.java---
False Positives and Negatives
Issue: Too many skills suggested
Symptom: Scanner suggests 5+ skills for a simple file.
Cause: File contains patterns from multiple domains.
Solution:
This is expected behavior. The scanner detects all applicable patterns. Focus on:
- HIGH RISK skills (security, testing, verify) that require confirmation
- LOW RISK skills are informational only
---
Issue: Wrong skill suggested
Symptom: Scanner suggests spring-boot-data-ddd for a service class.
Cause: Pattern overlap (e.g., @Repository can appear in different contexts).
Solution:
Consider the file's directory location:
**/domain/**→domain-driven-designskill**/repository/**→spring-boot-data-dddskill**/controller/**→spring-boot-web-apiskill
The scanner provides suggestions; use judgment based on context.
---
Issue: Missing escalation warnings
Symptom: Deprecated patterns not flagged.
Cause: Pattern not in escalation list or using different format.
Solution:
Escalation patterns are specific. Common variants that may not trigger:
| Detected | NOT Detected |
|---|---|
@MockBean | @org.springframework.boot.test.mock.mockito.MockBean |
.and() | and() (without dot) |
antMatchers | ant_matchers (different style) |
---
Using Exa MCP for Edge Cases
When encountering issues not covered here, use Exa MCP for latest information:
Use Exa MCP to search for: "Spring Boot [specific issue]"Examples:
- "Spring Boot 4 annotation detection patterns"
- "Spring Kotlin annotation processing"
- "Spring Boot custom annotation scanning"
Spring Boot Scanner Workflow
Detailed step-by-step detection and routing workflow.
Complete Detection Flow
┌─────────────────────────────────────────────────────────────────┐
│ TRIGGER: User Activity │
│ - Editing Java or Kotlin file │
│ - Discussing Spring Boot │
│ - Working with build files │
└───────────────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ PHASE 1: Spring Boot Project Detection │
│ │
│ 1. Glob for build files: │
│ - **/pom.xml │
│ - **/build.gradle* │
│ │
│ 2. Grep for Spring Boot indicators: │
│ - spring-boot-starter │
│ - org.springframework.boot │
│ │
│ Result: IS_SPRING_BOOT = true/false │
└───────────────────────────────┬─────────────────────────────────┘
│
┌─────────────────┴─────────────────┐
│ │
IS_SPRING_BOOT NOT SPRING_BOOT
│ │
▼ ▼
Continue to Phase 2 EXIT (no action)
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ PHASE 2: Annotation Pattern Scanning │
│ │
│ Target: Current file being edited OR recently changed files │
│ │
│ Scan for annotation categories: │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ WEB PATTERNS │ │ DATA PATTERNS │ │
│ │ @RestController │ │ @Entity │ │
│ │ @GetMapping │ │ @Repository │ │
│ │ @PostMapping │ │ @Aggregate │ │
│ │ @RequestMapping │ │ @MappedSuperclass│ │
│ │ @ResponseBody │ │ @EmbeddedId │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ SECURITY │ │ TESTING │ │
│ │ @EnableWebSec │ │ @SpringBootTest │ │
│ │ @PreAuthorize │ │ @WebMvcTest │ │
│ │ @Secured │ │ @DataJpaTest │ │
│ │ SecurityFilter │ │ @MockitoBean │ │
│ │ Chain │ │ @MockBean (dep) │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ MODULITH │ │ OBSERVABILITY │ │
│ │ @ApplicationMod │ │ @Timed │ │
│ │ @ApplicationMod │ │ @Counted │ │
│ │ uleListener │ │ HealthIndicator │ │
│ │ @NamedInterface │ │ MeterRegistry │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
│ ┌──────────────────┐ │
│ │ DDD PATTERNS │ │
│ │ @Service in │ │
│ │ domain/** │ │
│ │ @DomainService │ │
│ │ @ValueObject │ │
│ │ @AggregateRoot │ │
│ └──────────────────┘ │
│ │
│ Result: detected_patterns = [{skill, risk_level, patterns[]}] │
└───────────────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ PHASE 3: Risk Classification │
│ │
│ Categorize detected skills by risk: │
│ │
│ LOW_RISK = [ │
│ spring-boot-web-api, │
│ spring-boot-data-ddd, │
│ domain-driven-design, │
│ spring-boot-modulith, │
│ spring-boot-observability │
│ ] │
│ │
│ HIGH_RISK = [ │
│ spring-boot-security, │
│ spring-boot-testing, │
│ spring-boot-verify │
│ ] │
│ │
│ ESCALATION_TRIGGERS = [ │
│ @MockBean → deprecated warning │
│ @EnableGlobalMethodSecurity → deprecated warning │
│ .and() in security → removed warning │
│ com.fasterxml.jackson → migration warning │
│ version < 3.0 → major migration warning │
│ ] │
│ │
│ Separate patterns into: │
│ - low_risk_patterns[] │
│ - high_risk_patterns[] │
│ - escalation_patterns[] │
└───────────────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ PHASE 4: Routing & Response │
│ │
│ CASE 1: Only LOW_RISK patterns │
│ ──────────────────────────── │
│ → Auto-invoke relevant skill guidance │
│ → Format: "Working with [pattern]. Here's guidance:" │
│ → Load skill Quick Reference inline │
│ │
│ CASE 2: Only HIGH_RISK patterns │
│ ──────────────────────────── │
│ → Use AskUserQuestion to confirm │
│ → Options: │
│ - "Load [skill] for detailed guidance" │
│ - "Run verification scan" │
│ - "Continue without guidance" │
│ → Wait for user selection │
│ → Route based on choice │
│ │
│ CASE 3: Mixed LOW + HIGH risk │
│ ──────────────────────────── │
│ → Auto-invoke LOW_RISK guidance │
│ → Separately ask about HIGH_RISK │
│ → Format: "Loaded [low] guidance. For [high], would you like?" │
│ │
│ CASE 4: ESCALATION triggers present │
│ ──────────────────────────── │
│ → Always show warning first │
│ → Format: "⚠️ Detected deprecated pattern: [pattern]" │
│ → Recommend specific action │
│ → Then proceed with normal routing │
│ │
│ CASE 5: Many files / comprehensive request │
│ ──────────────────────────── │
│ → Delegate to spring-boot-reviewer agent │
│ → Format: "This requires comprehensive review. Launching..." │
│ → Use Agent tool to invoke agent │
└─────────────────────────────────────────────────────────────────┘Implementation Steps
Step 1: Detect Spring Boot Project
# Using Glob + Grep
1. files = Glob("**/pom.xml") + Glob("**/build.gradle*")
2. for file in files:
content = Read(file)
if "spring-boot-starter" in content or "org.springframework.boot" in content:
return IS_SPRING_BOOT = True
3. return IS_SPRING_BOOT = FalseStep 2: Scan for Annotations
# Using Grep with patterns
PATTERNS = {
"web-api": r"@RestController|@GetMapping|@PostMapping|@RequestMapping",
"data-ddd": r"@Entity|@Repository|@Aggregate|@MappedSuperclass",
"security": r"@EnableWebSecurity|@PreAuthorize|@Secured|SecurityFilterChain",
"testing": r"@SpringBootTest|@WebMvcTest|@DataJpaTest|@MockitoBean|@MockBean",
"modulith": r"@ApplicationModule|@ApplicationModuleListener|@NamedInterface",
"observability": r"@Timed|@Counted|HealthIndicator|MeterRegistry",
"ddd": r"@DomainService|@ValueObject|@AggregateRoot"
}
detected = []
for skill, pattern in PATTERNS.items():
matches = Grep(pattern, target_file)
if matches:
detected.append({"skill": skill, "matches": matches})Step 3: Classify and Route
LOW_RISK = ["web-api", "data-ddd", "ddd", "modulith", "observability"]
HIGH_RISK = ["security", "testing", "verify"]
low_risk_detected = [d for d in detected if d["skill"] in LOW_RISK]
high_risk_detected = [d for d in detected if d["skill"] in HIGH_RISK]
# Check for escalation triggers
escalations = check_escalation_triggers(target_file)
# Route based on classification
if escalations:
show_warnings(escalations)
if low_risk_detected:
auto_invoke_guidance(low_risk_detected)
if high_risk_detected:
ask_user_confirmation(high_risk_detected)Grep Patterns Reference
Note: All patterns work with both Java (*.java) and Kotlin (*.kt) files.
Web API Patterns
grep -E "@RestController|@GetMapping|@PostMapping|@PutMapping|@DeleteMapping|@PatchMapping|@RequestMapping|@ResponseBody|@RequestBody|@PathVariable|@RequestParam" **/*.java **/*.ktData/Repository Patterns
grep -E "@Entity|@Repository|@Aggregate|@MappedSuperclass|@EmbeddedId|@Embeddable|@OneToMany|@ManyToOne|@JoinColumn" **/*.java **/*.ktSecurity Patterns
grep -E "@EnableWebSecurity|@EnableMethodSecurity|@PreAuthorize|@PostAuthorize|@Secured|@RolesAllowed|SecurityFilterChain|AuthenticationManager|UserDetailsService" **/*.java **/*.ktTesting Patterns
grep -E "@SpringBootTest|@WebMvcTest|@DataJpaTest|@DataJdbcTest|@JsonTest|@MockitoBean|@MockBean|@SpyBean|@ServiceConnection|Testcontainers" **/*.java **/*.ktModulith Patterns
grep -E "@ApplicationModule|@ApplicationModuleListener|@NamedInterface|@Externalized|ApplicationModuleTest" **/*.java **/*.ktObservability Patterns
grep -E "@Timed|@Counted|@Observed|HealthIndicator|MeterRegistry|Tracer|Span|ObservationRegistry" **/*.java **/*.ktEscalation Triggers
# Deprecated patterns requiring immediate attention
grep -E "@MockBean|@EnableGlobalMethodSecurity|\.and\(\)|antMatchers|authorizeRequests|com\.fasterxml\.jackson" **/*.java **/*.ktModel Tier Performance
The scanner is designed for reliability across all model tiers:
| Aspect | Behavior |
|---|---|
| Haiku/Sonnet/Opus | All fully supported |
| Determinism | Python script ensures consistent results regardless of model |
| Single file scan | <100ms typical |
| Project scan | 1-2s for typical projects (recursive) |
The Python detection script handles heavy lifting, making results model-independent.
---
Response Templates
Low Risk Auto-Invoke Template
I notice you're working with {patterns}. Here's relevant guidance:
**From spring-boot-{skill}:**
- {quick reference point 1}
- {quick reference point 2}
- {quick reference point 3}
For detailed patterns, I can load the full skill guidance.High Risk Confirmation Template
I detected {patterns} in your code. This involves {security/testing/migration} considerations.
Would you like me to:
1. Load spring-boot-{skill} for detailed guidance
2. Run a comprehensive verification scan
3. Continue without additional guidance
[AskUserQuestion with these options]Escalation Warning Template
⚠️ **Deprecated Pattern Detected**
Found `{pattern}` which is {reason}.
**Recommended action:** {action}
**Migration:**// Before (deprecated) {old_code}
// After (current) {new_code}
Would you like me to help migrate this pattern?Delegation to Agent Template
This analysis requires reviewing multiple files. I'll delegate to the spring-boot-reviewer agent for a comprehensive scan.
**Scope:** {scope}
**Skills to check:** {relevant_skills}
Launching review...
[Agent tool to invoke spring-boot-reviewer agent]