From axoniq-framework-contribution
For Axon Framework contributors. Performs comprehensive code reviews against AF5 contributor standards: analyzes changed files, checks Antora documentation, verifies test coverage, and ensures compliance with AF5 patterns. Provides actionable fix suggestions that can be applied immediately.
How this skill is triggered — by the user, by Claude, or both
Slash command
/axoniq-framework-contribution:axoniq-framework-contribute-reviewThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill performs systematic code reviews following the comprehensive checklist compiled from Axon Framework review patterns. It not only identifies issues but **provides concrete fix suggestions** that can be applied immediately to the codebase.
This skill performs systematic code reviews following the comprehensive checklist compiled from Axon Framework review patterns. It not only identifies issues but provides concrete fix suggestions that can be applied immediately to the codebase.
This skill is designed to be helpful and actionable:
The skill performs a systematic review in the following order:
When issues are found, this skill provides an interactive workflow:
Skill: Found 3 issues. Here are suggested fixes:
FIX #1 (BLOCKING): Add missing @since tag
File: EventStore.java:456
Current:
/**
* Reads events from the store.
*/
public Stream<DomainEventMessage<?>> readEvents(String aggregateId) {
Suggested:
/**
* Reads events from the store.
*
* @since 5.1.0
*/
public Stream<DomainEventMessage<?>> readEvents(String aggregateId) {
User: Apply fix #1
Skill: ✅ Applied fix #1 to EventStore.java
User: Apply all remaining fixes
Skill: ✅ Applied fixes #2 and #3
Before anything else, determine which framework is being reviewed:
# Check package names to identify the framework
grep -r "^package " --include="*.java" | head -5
| Package prefix | Framework | License |
|---|---|---|
org.axonframework | Axon Framework | Apache 2.0 (OSS) |
io.axoniq.framework | Axoniq Framework | Commercial |
Feature boundary check — flag if a change seems misplaced:
Both frameworks share the same coding conventions. The review checklist applies equally to both.
First, determine the scope of changes:
# Check git status
git status --short
# Get diff stats
git diff --stat
# For PR reviews, compare against target branch
git diff main...HEAD --name-only
Before diving into detailed review, identify areas requiring extra scrutiny:
# Find files with significant changes (>50 lines)
git diff --stat | awk '$2 > 50 { print $1 " (" $2 " lines)" }'
# Find files with method signature changes
git diff | grep -B2 -A2 "^[+-].*public.*\(" | grep "^[+-]"
# Find new public classes/interfaces
git diff | grep "^+public class\|^+public interface"
# Check for files touching multiple concerns
git diff --name-only | while read f; do
echo "$f: $(git diff $f | grep -c '^@@')"
done | awk '$2 > 5'
Categorize hotspots by type:
For each hotspot, note:
Read all modified files to understand the changes:
Use the comprehensive checklist from ../../code-review-checklist.md to systematically review:
Reference Guide Documentation
/docs/reference-guide/modules/**/*.adocnav.adoc in the module/docs/reference-guide/modules/[module-name]/pages/Module Selection Guide:
events/ modulecommands/ modulequeries/ modulesagas/ modulemessaging-concepts/ moduledeadlines/ modulemonitoring/ moduletesting/ moduletuning/ modulemigration/ modulerelease-notes/ moduleJavaDoc Completeness
@since tags on new public/protected methods@author tags when refactoring code@Nullable annotations on nullable parameters/returns (under @NullMarked, non-null is the default)@Nonnull/@Nullable — these are forbidden by checkstyle@param/@return/@throws tags use fragment style (lowercase, no trailing period)Test Coverage
Configuration Class Testing (if configuration classes modified)
Breaking Changes
Fluent API Pattern (AF5 Style)
builder() patterns on infrastructure components../axon-framework-5-patterns/SKILL.mdNull Safety
Objects.requireNonNull at method/constructor entry)@Nullable on nullable parameters/return types (JSpecify; non-null is the default under @NullMarked)@Nonnull/@Nullable — use JSpecify insteadMethod Visibility
Error Handling
IllegalStateException, prefer AxonConfigurationException)Performance
LinkedList usage (suggest LinkedHashMap for lookups)Type Safety
Reference Guide Documentation Structure
# Check for reference guide documentation files
find docs/reference-guide/modules -name "*.adoc" -type f
# Look for navigation updates
grep -r "xref:" docs/reference-guide/modules/
# Check if nav.adoc was updated
git diff docs/reference-guide/modules/*/nav.adoc
JavaDoc Quality
Design Patterns
ConfigurationEnhancer usage for cross-cutting concernsDependencies
Review Hotspots (Areas requiring extra human attention) Identify classes/areas where code smells are most likely. Flag these for focused review:
Hotspot Indicators:
When to Flag as Hotspot:
# Check for large structural changes
git diff --stat | awk '$2 > 50 { print $1 }'
# Classes with method signature changes
git diff | grep -E "^[+-].*public.*\(" | sort | uniq -c
Report Format: Each hotspot should include:
Message Handler Wrapper Patterns (CRITICAL for handler enhancers)
instanceof to check handler types → Use canHandleMessageType()canHandleMessageType(MessageClass.class) to check compatibilityunwrap(SpecificType.class) only when accessing specific wrapper functionalityEventHandlingMember)@HasHandlerAttributes on annotations and check attributes (not annotations directly)MessageHandlingMember in method signatures, not specific handler typesCommon Issues to Flag:
// ❌ WRONG - instanceof breaks with generic wrappers
if (handler instanceof EventHandlingMember) { ... }
// ❌ WRONG - unwrapping loses wrapper chain behavior
EventHandlingMember unwrapped = handler.unwrap(EventHandlingMember.class).orElseThrow();
registerHandler(unwrapped); // Lost all wrapper behavior!
// ❌ WRONG - wrapper implements specific handler interface
class MyWrapper<T> extends WrappedMessageHandlingMember<T>
implements EventHandlingMember<T> { ... }
// ✅ CORRECT - canHandleMessageType works through wrappers
if (!handler.canHandleMessageType(EventMessage.class)) { ... }
// ✅ CORRECT - preserve wrapper chain
registerHandler(handler); // Pass full chain, unwrap only when needed
// ✅ CORRECT - wrapper doesn't implement specific interfaces
class MyWrapper<T> extends WrappedMessageHandlingMember<T> { ... }
Search patterns to detect issues:
# Find instanceof checks on handlers (likely wrong)
grep -r "instanceof.*HandlingMember" --include="*.java"
# Find handler unwrapping (review if wrapper chain is preserved)
grep -r "\.unwrap(.*HandlingMember\.class)" --include="*.java"
# Find wrappers that implement specific handler interfaces (likely wrong)
grep -A2 "extends WrappedMessageHandlingMember" --include="*.java" | grep "implements.*HandlingMember"
Create a structured report with concrete fix suggestions for each issue:
# Code Review Report
## Summary
- Files Changed: X
- Issues Found: Y total (Z blocking, W warnings, V suggestions)
- Review Hotspots: N (areas needing extra human attention)
- Fixes Available: [Number of automated fixes ready]
## SUGGESTED FIXES
### FIX #1 (BLOCKING): Add missing @since tag
**File:** `ComponentClass.java:456`
**Severity:** BLOCKING ❌
**Issue:** New public method without @since tag
**Why:** All public/protected methods must have @since tags per AF5 standards
**Current code:**
```java
/**
* Processes items from the specified source.
*/
public Stream<ResultMessage> process(String identifier) {
Suggested fix:
/**
* Processes items from the specified source.
*
* @param identifier the source identifier
* @return stream of result messages
* @since 5.1.0
*/
public Stream<ResultMessage> process(String identifier) {
To apply: Say "Apply fix #1" or "Apply all fixes"
File: ComponentConfig.java:123
Severity: WARNING ⚠️
Issue: Using generic exception for configuration error
Why: Configuration errors should use AxonConfigurationException for consistency
Current code:
throw new IllegalStateException("Component not configured");
Suggested fix:
throw new AxonConfigurationException("Component not configured");
Impact: Need to import org.axonframework.common.AxonConfigurationException
To apply: Say "Apply fix #2"
File: ComponentImpl.java:789
Severity: SUGGESTION 💡
Issue: Public method only used internally
Why: Minimizing public API surface improves maintainability
Current code:
public void validateInternalState(List<Message> items) {
Suggested fix:
protected void validateInternalState(List<Message> items) {
To apply: Say "Apply fix #3"
Issue: New feature added without user-facing documentation
Required: Add documentation in appropriate docs/reference-guide/modules/[module]/pages/
Should cover:
I can help create a documentation template. Say "Generate doc template for DOC #1"
Areas where code smells or design issues are most likely. Human reviewers should focus extra attention here:
File: AnnotatedEventHandlingComponent.java (124 lines changed)
Type: Structural + Core Logic
Why flagged: Central to this PR's handler wrapper chain preservation fix
Focus areas:
initializeHandlersBasedOnModel() - Changed from unwrapping to preserving wrapper chainregisterHandler() - Signature changed from EventHandlingMember to MessageHandlingMemberEventHandlingMember specificallyReview questions:
File: HandlerAttributes.java (2 constants added)
Type: API Addition
Why flagged: New public constants affect handler attribute contracts
Focus areas:
Review questions:
HandlerAttributes constants?BLOCKING (must fix before commit): 2
WARNINGS (should fix): 1
SUGGESTIONS (nice to have): 1
REVIEW HOTSPOTS (human attention needed): 2
🔥 Hotspots flag areas where code smells are most likely. These aren't necessarily bugs, but deserve extra scrutiny from human reviewers due to complexity, structural changes, or being core to the PR's purpose.
To fix all issues quickly:
[List with assessment]
## Severity Levels
### BLOCKING ❌
Issues that prevent approval:
- Missing Antora documentation for feature changes
- Missing or incomplete JavaDoc on public APIs
- Apparent lack of test coverage (<80%)
- Breaking changes without migration docs
- Security vulnerabilities
- Resource leaks
### WARNING ⚠️
Issues that should be addressed but may not block:
- Missing `@author` tags
- Method visibility could be reduced
- Performance concerns (non-critical)
- Code duplication
- Missing null safety annotations
### SUGGESTION 💡
Improvements and best practices:
- Better naming
- Additional test cases
- Code organization
- Documentation enhancements
## Quick Review Mode
For a fast review focusing only on critical items:
```bash
# Check for doc changes
git diff --name-only | grep "^docs/"
# Check for test files
git diff --name-only | grep "Test.java$"
# Check for breaking changes
git diff | grep -E "(@Deprecated|public.*\(|protected.*\()"
Then apply only the BLOCKING checklist items.
For a thorough review:
code-review-checklist.mdaxon-framework-5-patterns skill/docs for new documentation@author tags preserved or updatedFor each issue, provide:
### FIX #[N] ([SEVERITY]): [Brief Title]
**File:** `[file.java:line]`
**Severity:** [BLOCKING/WARNING/SUGGESTION] [emoji]
**Issue:** [What's wrong]
**Why:** [Explain the reasoning - reference standards/patterns]
**Current code:**
```java
[actual code from file]
Suggested fix:
[corrected code]
Impact: [Any imports needed, side effects, or considerations] To apply: Say "Apply fix #[N]"
### Types of Fixes to Generate
#### 1. JavaDoc Fixes (Very Common)
**Easy to automate:** YES
- Add missing `@since` tags
- Add missing `@author` tags
- Add missing `@param` or `@return` docs
- Fix sentence-style capitalization in parameter docs
- Add constructor javadoc with defaults
- Clarify ambiguous terminology
**Example - Method JavaDoc:**
```java
// Before
/**
* Processes items.
*/
public Stream<ResultMessage> process(String identifier) {
// After
/**
* Processes items from the specified source.
*
* @param identifier the source identifier
* @return stream of result messages
* @since 5.1.0
*/
public Stream<ResultMessage> process(String identifier) {
Example - Constructor JavaDoc:
// Before
public ComponentConfiguration() {
// After
/**
* Constructs a default {@code ComponentConfiguration} with the following settings:
* <ul>
* <li>Thread count: 10</li>
* <li>Queue capacity: 1000</li>
* <li>Auto-retry: enabled</li>
* </ul>
*/
public ComponentConfiguration() {
Example - Terminology Clarity:
// Before (ambiguous - "prefer" could mean priority)
/**
* Indicates whether local handlers are preferred over remote ones.
*/
// After (clear - explains fallback behavior)
/**
* Indicates whether local handlers are used directly when available, bypassing
* remote dispatch. When no local handler is available, the request is dispatched
* remotely through the connector.
*/
Easy to automate: YES
@Nullable for parameters/return values that may be nullpackage-info.java has @NullMarked (non-null is the default under it)Example — missing @Nullable:
// Before (nullable parameter not marked)
public void process(String id, Object payload) {
// After (JSpecify — only @Nullable needed, non-null is default under @NullMarked)
public void process(String id, @Nullable Object payload) {
Impact: May need to add import org.jspecify.annotations.Nullable; and ensure package-info.java has @NullMarked.
Example — wrong annotation library:
// ❌ WRONG — jakarta annotations are forbidden
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
// ✅ CORRECT — use JSpecify
import org.jspecify.annotations.Nullable;
// (non-null is default under @NullMarked — no @Nonnull needed)
Easy to automate: YES
AxonConfigurationExceptionExample:
// Before
throw new IllegalStateException("EventStore not configured");
// After
throw new AxonConfigurationException("EventStore not configured");
Impact: Need import org.axonframework.common.AxonConfigurationException;
Easy to automate: YES (but verify intent first)
Example:
// Before
public void internalHelper() {
// After
protected void internalHelper() {
Caveat: Ask if unsure whether method is part of public API
Moderate automation: Requires understanding usage
LinkedList with LinkedHashMap for lookup-heavy codeExample:
// Before
private final LinkedList<Item> cache = new LinkedList<>();
// ... frequent lookups with cache.contains()
// After
private final LinkedHashMap<String, Item> cache = new LinkedHashMap<>();
Impact: May need to adjust add/remove logic
Easy to automate: YES
Example:
// Before
if (token instanceof MultiSourceToken) {
MultiSourceToken mst = (MultiSourceToken) token;
return mst.getPosition();
}
// After
if (token instanceof MultiSourceToken mst) {
return mst.getPosition();
}
Easy to automate: YES (Common in HandlerEnhancerDefinition implementations)
instanceof checks with canHandleMessageType()Example 1 - Type Check:
// Before
@Override
public <T> MessageHandlingMember<T> wrapHandler(@Nonnull MessageHandlingMember<T> original) {
if (original instanceof EventHandlingMember) {
return new MyWrapper<>(original);
}
return original;
}
// After
@Override
public <T> MessageHandlingMember<T> wrapHandler(@Nonnull MessageHandlingMember<T> original) {
if (!original.canHandleMessageType(EventMessage.class)) {
return original;
}
return new MyWrapper<>(original);
}
Example 2 - Preserve Wrapper Chain:
// Before
private void initializeHandlers() {
model.getUniqueHandlers(targetClass, EventMessage.class)
.forEach(handler -> {
// Loses wrapper chain!
EventHandlingMember<T> eventHandler = handler.unwrap(EventHandlingMember.class)
.orElseThrow(...);
registerHandler(eventHandler);
});
}
// After
private void initializeHandlers() {
model.getUniqueHandlers(targetClass, EventMessage.class)
.forEach(handler -> {
// Preserves wrapper chain
if (!handler.canHandleMessageType(EventMessage.class)) {
throw new IllegalStateException(...);
}
registerHandler(handler); // Pass full chain
});
}
// Update method signature
private void registerHandler(MessageHandlingMember<? super T> handler) { // Not EventHandlingMember
// Can unwrap to specific types when needed
Optional<SequencingPolicy> policy = handler.unwrap(SequencingPolicyMember.class)
.map(SequencingPolicyMember::sequencingPolicy);
// ...
}
Example 3 - Wrapper Class Definition:
// Before
private static class MyWrapper<T> extends WrappedMessageHandlingMember<T>
implements EventHandlingMember<T> { // Don't implement specific interfaces
// ...
}
// After
private static class MyWrapper<T> extends WrappedMessageHandlingMember<T> {
// No need to implement EventHandlingMember - unwrap() handles it
// ...
}
Impact:
EventHandlingMember to MessageHandlingMemberimport org.axonframework.messaging.eventhandling.EventMessage;instanceof checks should be updated to use unwrap() patternComplex: Requires significant refactoring
Example:
FIX #5 (WARNING): Convert to AF5 fluent style
This requires refactoring the builder pattern. I can help with this.
See: .claude/skills/axon-framework-5-patterns/SKILL.md
Would you like me to refactor this builder to AF5 style?
When multiple fixes are available:
When user requests a fix:
Example Application:
User: Apply fix #1
Skill:
✅ Applied FIX #1: Added @since 5.1.0 tag to EventStore.readEvents()
File: EventStore.java:456
Remaining fixes: 3 (1 blocking, 2 warnings)
Would you like to apply more? Say "Apply fix #2" or "Apply all remaining"
Some issues require discussion, not automatic fixes:
For these, provide guidance instead:
DOC #1 (BLOCKING): Add Antora documentation
**Required:** Documentation in docs/reference-guide/modules/events/pages/
I can generate a documentation template covering:
- Feature overview
- Usage examples
- Code samples
Say "Generate doc template for DOC #1" and I'll create a starting point.
Support these batch commands:
When reviewing tests, assess the quality of test object creation:
Prefer this hierarchy:
Example - Real objects (PREFERRED):
// ✅ Use real message objects with factory methods
private static QueryMessage queryMessage(QualifiedName name) {
return new GenericQueryMessage(new MessageType(name), "test-payload");
}
// In test:
QueryMessage query = queryMessage(new QualifiedName("TestQuery"));
Example - Stub implementations (GOOD):
// ✅ Stub for tracking behavior
private static class StubConnector implements BusConnector {
final Set<QualifiedName> subscriptions = new HashSet<>();
final AtomicInteger callCount = new AtomicInteger(0);
@Override
public void subscribe(QualifiedName name) {
subscriptions.add(name);
callCount.incrementAndGet();
}
}
Example - Mocks (USE SPARINGLY):
// ⚠️ Only when necessary for complex verification
BusConnector connector = mock(BusConnector.class);
verify(connector).subscribe(eq(queryName));
Check that tests clean up resources:
Pattern verification:
// ✅ Good - cleanup in finally block
@Test
void testExecutorCreation() {
ExecutorService executor = component.createExecutor();
try {
// test assertions
} finally {
executor.shutdown();
}
}
// ✅ Good - cleanup in @AfterEach
@AfterEach
void cleanup() {
if (executorService != null) {
executorService.shutdown();
}
}
When reviewing builder patterns or infrastructure components:
Invoke: axon-framework-5-patterns
Then: code-review
After staging changes but before committing:
Run: /code-review
The complete review checklist is available in:
../../code-review-checklist.md
This includes:
While performing the review, remind about these automated checks:
# SonarQube (CI will run this)
# - Coverage: ≥ 80% on new code
# - Duplication: ≤ 3%
# - Reliability: A rating
# - Security: A rating
# Documentation linting
# - Vale linter for Antora docs
# - Run on CI
# Build verification
# - All modules build successfully
# - No compiler warnings
User: /code-review
Skill: [Checks git status, reads changed files, applies checklist, generates report]
User: /code-review feature/my-feature
Skill: [Compares against main branch, performs comprehensive review]
User: /code-review --quick
Skill: [Runs only BLOCKING checks for fast feedback]
The skill will output an interactive, actionable review report with:
Example:
# Code Review Report
## Summary
- Files Changed: 3
- Issues Found: 4 (2 blocking, 1 warning, 1 suggestion)
- Automated Fixes Available: 3
---
## SUGGESTED FIXES
### FIX #1 (BLOCKING): Add missing @since tag
**File:** `EventStore.java:456`
**Issue:** New public method without @since tag
**Why:** All public/protected members must have @since tags (AF5 standard)
**Current code:**
```java
/**
* Reads events from the store.
*/
public Stream<DomainEventMessage<?>> readEvents(String aggregateId) {
Suggested fix:
/**
* Reads events from the store.
*
* @param aggregateId the aggregate identifier
* @return stream of domain events for the aggregate
* @since 5.1.0
*/
public Stream<DomainEventMessage<?>> readEvents(String aggregateId) {
To apply: Say "Apply fix #1" or "Apply all fixes"
File: EventStoreConfig.java:123
Issue: Generic exception for configuration error
Why: Use AxonConfigurationException for consistency
Current code:
throw new IllegalStateException("EventStore not configured");
Suggested fix:
throw new AxonConfigurationException("EventStore not configured");
Impact: Add import org.axonframework.common.AxonConfigurationException
To apply: Say "Apply fix #2"
File: EventStoreImpl.java:789
Issue: Public method only used internally
Why: Minimize public API surface
Current code:
public void validateEventSequence(List<DomainEventMessage<?>> events) {
Suggested fix:
protected void validateEventSequence(List<DomainEventMessage<?>> events) {
To apply: Say "Apply fix #3"
Issue: New feature without user-facing documentation Required: Documentation in docs/reference-guide/modules/events/pages/ Should cover:
Action: Say "Generate doc template for DOC #1" for a starting point
Ready to fix these issues?
Current Status: 2 BLOCKING issues (1 fix available, 1 needs docs) After applying all fixes: 1 BLOCKING issue remaining (DOC #1)
## Tips for Effective Reviews
1. **Read the checklist first** - Familiarize yourself with common issues
2. **Focus on blocking items initially** - Don't let perfect be the enemy of good
3. **Provide specific file:line references** - Make it easy to find issues
4. **Suggest solutions** - Don't just point out problems
5. **Acknowledge good work** - Positive findings motivate
6. **Be constructive** - Frame feedback as improvements, not criticisms
7. **Consider context** - Understand the intent before suggesting changes
## Review Report Template
See `templates/review-report-template.md` for a reusable report structure.
## Frequently Checked Items
Based on analysis of 20+ PRs, these are checked most frequently:
1. ✅ `@since` tags on new public/protected members (VERY COMMON)
2. ✅ `@author` tags when refactoring (COMMON)
3. ✅ Antora documentation in `/docs` (CRITICAL)
4. ✅ Test coverage ≥ 80% (ENFORCED)
5. ✅ JSpecify `@Nullable` on nullable params/returns; `@NullMarked` on packages (Jakarta forbidden)
6. ✅ Use `AxonConfigurationException` not generic exceptions
7. ✅ Method visibility minimized
8. ✅ No `LinkedList` for lookup-heavy operations
9. ✅ Breaking changes justified and documented
10. ✅ Resource cleanup (try-with-resources)
---
*This skill references: `../../code-review-checklist.md` for comprehensive criteria*
*Related skills: `axon-framework-5-patterns` for API design validation*
npx claudepluginhub axoniq/agent-skills --plugin axoniq-framework-contributionGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.