Install
$ agentstack add skill-axoniq-agent-skills-axoniq-framework-contribute-code ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Axon Framework Core Component Development
This skill guides development of Axon Framework infrastructure components, focusing on API design patterns, component lifecycle, and framework-specific conventions. The core philosophy, conventions, checklist, and anti-patterns are below; detailed patterns with full code examples live in references/ — load them via the routing table when working on that topic.
When to Use This Skill
- Designing new infrastructure components (buses, stores, handlers)
- Creating layered APIs (low-level + high-level abstractions)
- Implementing component builders and configuration
- Designing extension points (SPI vs API)
- Ensuring thread safety and lifecycle management
- Reviewing core framework code for consistency
Note: This is for developing the Axon/Axoniq frameworks themselves, not for using them in applications.
Framework Selection: Axon Framework vs Axoniq Framework
Two related frameworks share the conventions in this skill. Before contributing, understand which repo you're working in and what belongs where.
| | Axon Framework | Axoniq Framework | |---|---|---| | License | Apache 2.0 (open source) | Commercial (free for development) | | Package prefix | org.axonframework | io.axoniq.framework | | Repo | axon-5.0 | axoniq-framework | | Maven group | org.axonframework | io.axoniq.framework |
What Belongs in Each Framework
Axon Framework (OSS) — foundational building blocks:
- Core messaging infrastructure:
CommandBus,EventBus,QueryBus - Event sourcing:
EventStore,EventStorageEngine,EventSourcingRepository - Domain modelling:
Repository,EntityMetamodel,StateManager - Basic Spring Boot integration (
extensions/spring) - Metrics (Micrometer/Dropwizard) extensions
- Test utilities and BDD fixtures (
test/module) - Axon Server connector (basic)
Axoniq Framework (Commercial) — production enhancements on top:
- Dead-Letter Queue (
SequencedDeadLetterQueue, JDBC/JPA implementations) - PostgreSQL storage engine (
PostgresqlEventStorageEngine) - Distributed messaging enhancements (
DistributedCommandBus,DistributedQueryBus) - Multi-source event streaming (
MultiStreamableEventSource,MultiSourceTrackingToken) - Message transformation / upcasting (
EventTransformation,EventTransformerChain) - Spring Boot auto-configuration out of the box
- Enhanced Axon Server connector with additional features (persistent streams)
Informing Users About Options
When a user asks about a feature that has both OSS and commercial options, always present both fairly:
- Axon Framework alone is sufficient for many use cases including production deployments
- Axoniq Framework adds production conveniences (Spring auto-config, DLQ, PostgreSQL, distributed messaging)
- Do not assume users need or want the commercial framework
- Let users make an informed choice based on their actual needs
Core Design Philosophy
Axon Framework uses a three-tier architecture for component APIs:
┌─────────────────────────────────────────┐
│ Level 3: Context-Scoped Components │ ← Specialized, lifecycle-bound
│ (EventAppender, etc.) │
├─────────────────────────────────────────┤
│ Level 2: High-Level APIs (Gateways) │ ← User-friendly, convenience
│ (EventGateway, CommandGateway) │
├─────────────────────────────────────────┤
│ Level 1: Low-Level Infrastructure │ ← Raw concepts, composable
│ (EventBus, EventSink, CommandBus) │
└─────────────────────────────────────────┘
Key Principle: Each layer builds on the one below it. Users typically interact with Level 2 or 3, while framework developers implement Level 1. See references/layered-api-design.md for the design rules per level.
Coding Conventions (always apply)
Nullability — JSpecify, annotated at the package level with @NullMarked:
// ✅ CORRECT — in package-info.java
@NullMarked
package org.axonframework.messaging.core;
import org.jspecify.annotations.NullMarked;
Under @NullMarked, all parameters and return values are non-null by default. Only mark nullable exceptions with @Nullable (from org.jspecify.annotations). Enforce non-null contracts at runtime with Objects.requireNonNull(param, "Param may not be null"). Jakarta annotations (jakarta.annotation.*) are explicitly forbidden (enforced by checkstyle).
Modern Java — use pattern matching with instanceof:
// ✅ PREFERRED
if (trackingToken instanceof MultiSourceTrackingToken multiSourceToken) {
return open(multiSourceToken, condition, context);
}
Routing Table
Read the reference file for the topic you're working on. Each contains full design rules, code templates, and worked examples.
| Topic | When to read | Reference file | |---|---|---| | Layered API design (Level 1/2/3), interface composition, DescribableComponent | Designing any new component or its public API | references/layered-api-design.md | | Fluent builders (AF5 style), defaults vs forced choices, type-state builders, builder tests | Adding a factory/builder API or configuration entry point | references/fluent-builders.md | | Immutable configuration classes, ComponentBuilder, ModuleBuilder | Writing a *Configuration class or module wiring | references/configuration-classes.md | | Registration, ProcessingLifecycle phases, ResourceKey, component resolution | Components with subscriptions, transactional hooks, or context-scoped state | references/lifecycle-and-context.md | | Thread safety: immutability, concurrent collections, lock-free patterns | Any component with shared mutable state | references/thread-safety.md | | SPI vs API separation (@Internal), parameter validation, exception design | Defining extension points or error handling | references/spi-api-validation.md | | Test object creation (real > stub > mock), resource cleanup in tests | Writing or reviewing tests for framework components | references/testing.md | | Message handler wrappers: unwrap(), canHandleMessageType(), attribute-based config | Touching MessageHandlingMember, handler definitions, or handler enhancers | references/handler-wrappers.md |
Design Checklist for New Components
API Design
- [ ] Identify abstraction level (low/high/context-scoped)
- [ ] Low-level: works with Message types, explicit context
- [ ] High-level: accepts Objects, optional context, many overloads
- [ ] Context-scoped: static forContext(), void returns
- [ ] Use interface composition where appropriate
- [ ] Extend DescribableComponent
Configuration
- [ ] Provide sensible defaults when obvious
- [ ] Force choices with phased builders when not obvious
- [ ] Use ComponentBuilder for dependency injection
- [ ] Validate all constructor parameters with requireNonNull
- [ ] Include descriptive error messages
AF5 Fluent Builders (if applicable)
- [ ] Use descriptive static factory (not
builder()) - [ ] Create public intermediate builder interface
- [ ] Provide descriptive terminal operations
- [ ] Validate parameters early (in
and()not at terminal) - [ ] Return unmodifiable collections
- [ ] Add package-private accessor for testing
- [ ] Use JSpecify
@NullMarkedat package level,@Nullablefor nullable params/returns (neverjakarta.annotation) - [ ] Use modern Java patterns (pattern matching instanceof)
- [ ] Organize tests with
@Nestedclasses - [ ] Test actual internal state, not just non-null
- [ ] Test immutability of returned collections
Lifecycle
- [ ] Return Registration for subscriptions
- [ ] Integrate with ProcessingLifecycle for transactional behavior
- [ ] Use ResourceKey for context-scoped resources
- [ ] Implement proper cleanup in Registration.cancel()
Thread Safety
- [ ] Prefer immutability
- [ ] Use ConcurrentHashMap for subscription registries
- [ ] Use CopyOnWriteArrayList for listener lists
- [ ] Use AtomicReference for mutable state
- [ ] Document thread safety in JavaDoc
SPI vs API
- [ ] Mark SPIs with @Internal
- [ ] Keep public API simple and user-focused
- [ ] Implementation class connects API to SPI
- [ ] SPIs allow extensibility, APIs ensure usability
Error Handling
- [ ] Validate all parameters immediately
- [ ] Use specific exception types
- [ ] Include context in exception messages
- [ ] Use AxonConfigurationException for config errors
Documentation
- [ ] JavaDoc on all public interfaces and methods
- [ ] @since tags on new APIs
- [ ] @author tags when appropriate
- [ ] Code examples for complex components
- [ ] Update reference guide in docs/reference-guide/modules
Anti-Patterns to Avoid
❌ Builder Pattern on Infrastructure Components
Don't:
MyComponent.builder().withX(x).withY(y).build();
Do:
// AF5 fluent style
MyComponent.configuring("name").withX(x).withY(y).initialize();
See references/fluent-builders.md for the full pattern.
❌ Mutable Message Objects
Don't:
eventMessage.setMetadata(newMetadata); // Mutation
Do:
EventMessage updated = eventMessage.withMetadata(newMetadata); // New instance
❌ Public Constructors for Context-Scoped Components
Don't:
public EventAppender(ProcessingContext context) { ... }
// Users might create multiple instances per context
Do:
private EventAppender(ProcessingContext context) { ... } // Private
public static EventAppender forContext(ProcessingContext context) {
return context.computeResourceIfAbsent(RESOURCE_KEY,
() -> new EventAppender(context));
}
❌ Swallowing Exceptions
Don't:
try {
storage.save(event);
} catch (Exception e) {
logger.warn("Failed to save", e); // Lost!
}
Do:
try {
storage.save(event);
} catch (StorageException e) {
throw new EventStoreException("Failed to save event: " + event.getIdentifier(), e);
}
❌ Synchronous Blocking in Async Methods
Don't:
public CompletableFuture publish(ProcessingContext context, List events) {
storage.save(events); // Blocks!
return CompletableFuture.completedFuture(null);
}
Do:
public CompletableFuture publish(ProcessingContext context, List events) {
return CompletableFuture.supplyAsync(() -> storage.save(events), executor)
.thenApply(result -> null);
}
❌ instanceof Checks on Message Handlers
Use canHandleMessageType() and unwrap() instead — see references/handler-wrappers.md.
Related Skills
- axoniq-framework-contribute-review: Review changes against AF5 contributor standards
- axoniq-framework-contribute-docs: Add or update the Antora reference documentation
Where to Find the Real Code
- Core interfaces:
messaging/src/main/java/org/axonframework/messaging/ - Gateway implementations:
messaging/src/main/java/org/axonframework/*/gateway/ - Event store:
eventsourcing/src/main/java/org/axonframework/eventsourcing/eventstore/ - Context:
messaging/src/main/java/org/axonframework/messaging/core/ - Configuration:
common/src/main/java/org/axonframework/common/configuration/ - Handler wrappers:
messaging/src/main/java/org/axonframework/messaging/*/annotation/
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: AxonIQ
- Source: AxonIQ/agent-skills
- License: Apache-2.0
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.