This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-java.git
The following commit(s) were added to refs/heads/main by this push:
new 2a61027e5e Add CLAUDE.md for AI assistant guidance (#786)
2a61027e5e is described below
commit 2a61027e5eb74ed1258c764ae2ffeabd499416a6
Author: 吴晟 Wu Sheng <[email protected]>
AuthorDate: Tue Jan 20 21:37:22 2026 +0800
Add CLAUDE.md for AI assistant guidance (#786)
Add a comprehensive guide for AI assistants working with the SkyWalking
Java Agent codebase, including:
- Project overview and repository structure
- Build system and commands
- Plugin development with V2 API (recommended) vs V1 API (legacy)
- Plugin development rules and dependency management
- Tracing concepts and meter APIs
- Plugin test framework documentation
- Code style and conventions
- PR guidelines and templates
---
CHANGES.md | 1 +
CLAUDE.md | 697 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 698 insertions(+)
diff --git a/CHANGES.md b/CHANGES.md
index 54f75eeb97..979502ce7a 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -5,6 +5,7 @@ Release Notes.
9.6.0
------------------
+* Add CLAUDE.md for AI assistant guidance.
* Bump up agent-oap protocol to
latest(16c51358ebcf42629bf4ffdf952253971f20eb25).
* Bump up gRPC to v1.74.0.
* Bump up netty to v4.1.124.Final.
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000000..90e3bf0f6c
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,697 @@
+# CLAUDE.md - AI Assistant Guide for Apache SkyWalking Java Agent
+
+This file provides guidance for AI assistants working with the Apache
SkyWalking Java Agent codebase.
+
+## Project Overview
+
+Apache SkyWalking Java Agent is a Java-based APM (Application Performance
Monitoring) agent designed for microservices, cloud-native, and container-based
architectures. It provides automatic instrumentation for distributed tracing,
performance metrics collection, and context propagation across service
boundaries using bytecode manipulation via ByteBuddy.
+
+## Repository Structure
+
+```
+skywalking-java/
+├── apm-commons/ # Shared utilities and libraries
+│ ├── apm-datacarrier/ # Data buffering and transport
+│ └── apm-util/ # Common utilities
+├── apm-protocol/ # Protocol definitions
+│ └── apm-network/ # gRPC protocol (submodule:
skywalking-data-collect-protocol)
+├── apm-sniffer/ # Core agent and plugins (MAIN MODULE)
+│ ├── apm-agent/ # Main agent bootstrap and premain entry
+│ ├── apm-agent-core/ # Core agent logic, instrumentation engine
+│ ├── apm-sdk-plugin/ # Standard SDK plugins (70+ plugins)
+│ ├── bootstrap-plugins/ # Bootstrap-level plugins (JDK-level)
+│ ├── optional-plugins/ # Optional framework plugins
+│ ├── optional-reporter-plugins/ # Reporter plugins (Kafka, etc.)
+│ ├── apm-toolkit-activation/ # Toolkit activations
+│ ├── apm-test-tools/ # Testing utilities
+│ ├── bytebuddy-patch/ # ByteBuddy patches
+│ └── config/ # Default agent configurations
+├── apm-application-toolkit/ # Public API for applications
+│ ├── apm-toolkit-trace/ # Tracing API
+│ ├── apm-toolkit-log4j-1.x/ # Log4j 1.x integration
+│ ├── apm-toolkit-log4j-2.x/ # Log4j 2.x integration
+│ ├── apm-toolkit-logback-1.x/ # Logback integration
+│ ├── apm-toolkit-meter/ # Meter API
+│ └── apm-toolkit-opentracing/ # OpenTracing API
+├── apm-checkstyle/ # Code style configuration
+│ ├── checkStyle.xml # Checkstyle rules
+│ └── importControl.xml # Import control rules
+├── test/ # Testing infrastructure
+│ ├── plugin/ # Plugin E2E tests
+│ │ ├── scenarios/ # Test scenarios (100+ scenarios)
+│ │ ├── agent-test-tools/ # Mock collector, test utilities
+│ │ ├── runner-helper/ # Test runner
+│ │ └── containers/ # Docker test containers
+│ └── e2e/ # End-to-end tests
+├── docs/ # Documentation
+├── tools/ # Build and utility tools
+├── skywalking-agent/ # Built agent distribution output
+├── changes/ # Changelog
+└── dist-material/ # Distribution materials
+```
+
+## Build System
+
+### Prerequisites
+- JDK 8, 11, 17, 21, or 25
+- Maven 3.6+
+- Git (with submodule support)
+
+### Common Build Commands
+
+```bash
+# Clone with submodules
+git clone --recurse-submodules https://github.com/apache/skywalking-java.git
+
+# Or initialize submodules after clone
+git submodule init && git submodule update
+
+# Full build with tests
+./mvnw clean install
+
+# Build without tests (recommended for development)
+./mvnw clean package -Dmaven.test.skip=true
+
+# CI build with javadoc verification
+./mvnw clean verify install javadoc:javadoc
+
+# Run checkstyle only
+./mvnw checkstyle:check
+
+# Build with submodule update
+./mvnw clean package -Pall
+
+# Docker build
+make build
+make docker
+```
+
+### Maven Profiles
+- `all`: Includes git submodule update for protocol definitions
+
+### Key Build Properties
+- ByteBuddy: 1.17.6 (bytecode manipulation)
+- gRPC: 1.74.0 (communication protocol)
+- Netty: 4.1.124.Final (network framework)
+- Protobuf: 3.25.5 (protocol buffers)
+- Lombok: 1.18.42 (annotation processing)
+
+## Architecture & Key Concepts
+
+### Agent Architecture
+The agent uses ByteBuddy for bytecode manipulation at runtime:
+
+1. **Premain Entry**: `apm-agent/` contains the agent bootstrap via Java's
`-javaagent` mechanism
+2. **Instrumentation Engine**: `apm-agent-core/` handles class transformation
and plugin loading
+3. **Plugins**: Define which classes/methods to intercept and how to collect
telemetry
+
+### Plugin Categories
+
+**1. SDK Plugins** (`apm-sniffer/apm-sdk-plugin/`)
+- Framework-specific instrumentations (70+ plugins)
+- Examples: grpc-1.x, spring, dubbo, mybatis, mongodb, redis, etc.
+- Pattern: One directory per library/framework version
+
+**2. Bootstrap Plugins** (`apm-sniffer/bootstrap-plugins/`)
+- Load at JVM bootstrap phase for JDK-level instrumentation
+- Examples: jdk-threading, jdk-http, jdk-httpclient,
jdk-virtual-thread-executor
+
+**3. Optional Plugins** (`apm-sniffer/optional-plugins/`)
+- Not included by default, user must copy to plugins directory
+
+**4. Optional Reporter Plugins** (`apm-sniffer/optional-reporter-plugins/`)
+- Alternative data collection backends (e.g., Kafka)
+
+### Plugin Instrumentation APIs (v1 vs v2)
+
+The agent provides two instrumentation APIs. **V2 is recommended** for all new
plugins; v1 is legacy and should only be used for maintaining existing plugins.
+
+#### V2 API (Recommended)
+
+V2 provides a `MethodInvocationContext` that is shared across all interception
phases (`beforeMethod`, `afterMethod`, `handleMethodException`), allowing you
to pass data (e.g., spans) between phases.
+
+**Instrumentation class (extends `ClassEnhancePluginDefineV2`):**
+```java
+public class XxxInstrumentation extends
ClassInstanceMethodsEnhancePluginDefineV2 {
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName("target.class.Name");
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] { ... };
+ }
+
+ @Override
+ public InstanceMethodsInterceptV2Point[]
getInstanceMethodsInterceptV2Points() {
+ return new InstanceMethodsInterceptV2Point[] {
+ new InstanceMethodsInterceptV2Point() {
+ @Override
+ public ElementMatcher<MethodDescription> getMethodsMatcher() {
+ return named("targetMethod");
+ }
+
+ @Override
+ public String getMethodsInterceptorV2() {
+ return
"org.apache.skywalking.apm.plugin.xxx.XxxInterceptor";
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
+```
+
+**Interceptor class (implements `InstanceMethodsAroundInterceptorV2`):**
+```java
+public class XxxInterceptor implements InstanceMethodsAroundInterceptorV2 {
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[]
allArguments,
+ Class<?>[] argumentsTypes,
MethodInvocationContext context) {
+ // Create span and store in context for later use
+ AbstractSpan span = ContextManager.createLocalSpan("operationName");
+ context.setContext(span); // Pass to afterMethod/handleMethodException
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method,
Object[] allArguments,
+ Class<?>[] argumentsTypes, Object ret,
MethodInvocationContext context) {
+ // Retrieve span from context
+ AbstractSpan span = (AbstractSpan) context.getContext();
+ span.asyncFinish();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method,
Object[] allArguments,
+ Class<?>[] argumentsTypes, Throwable t,
MethodInvocationContext context) {
+ AbstractSpan span = (AbstractSpan) context.getContext();
+ span.log(t);
+ }
+}
+```
+
+**Key V2 classes:**
+- `ClassEnhancePluginDefineV2` - Base class for plugins with both instance and
static methods
+- `ClassInstanceMethodsEnhancePluginDefineV2` - For instance methods only
+- `ClassStaticMethodsEnhancePluginDefineV2` - For static methods only
+- `InstanceMethodsAroundInterceptorV2` - Interceptor interface with
`MethodInvocationContext`
+- `StaticMethodsAroundInterceptorV2` - Static method interceptor with context
+
+#### V1 API (Legacy)
+
+V1 uses `MethodInterceptResult` only in `beforeMethod` and has no shared
context between phases. **Only use for maintaining existing legacy plugins.**
+
+**Key V1 classes (legacy):**
+- `ClassEnhancePluginDefine`
+- `ClassInstanceMethodsEnhancePluginDefine`
+- `ClassStaticMethodsEnhancePluginDefine`
+- `InstanceMethodsAroundInterceptor`
+- `StaticMethodsAroundInterceptor`
+
+### Plugin Development Rules
+
+#### Class Matching Restrictions
+
+**CRITICAL: Never use `.class` references in instrumentation definitions:**
+```java
+// WRONG - will break the agent if ThirdPartyClass doesn't exist
+takesArguments(ThirdPartyClass.class)
+byName(ThirdPartyClass.class.getName())
+
+// CORRECT - use string literals
+takesArguments("com.example.ThirdPartyClass")
+byName("com.example.ThirdPartyClass")
+```
+
+**ClassMatch options:**
+- `byName(String)`: Match by full class name (package + class name) -
**preferred**
+- `byClassAnnotationMatch`: Match classes with specific annotations (does NOT
support inherited annotations)
+- `byMethodAnnotationMatch`: Match classes with methods having specific
annotations
+- `byHierarchyMatch`: Match by parent class/interface - **avoid unless
necessary** (performance impact)
+
+#### Witness Classes/Methods
+
+Use witness classes/methods to activate plugins only for specific library
versions:
+```java
+@Override
+protected String[] witnessClasses() {
+ return new String[] { "com.example.VersionSpecificClass" };
+}
+
+@Override
+protected List<WitnessMethod> witnessMethods() {
+ return Collections.singletonList(
+ new WitnessMethod("com.example.SomeClass",
ElementMatchers.named("specificMethod"))
+ );
+}
+```
+
+#### Bootstrap Instrumentation
+
+For JDK core classes (rt.jar), override `isBootstrapInstrumentation()`:
+```java
+@Override
+public boolean isBootstrapInstrumentation() {
+ return true;
+}
+```
+**WARNING**: Use bootstrap instrumentation only where absolutely necessary.
+
+#### Plugin Configuration
+
+Use `@PluginConfig` annotation for custom plugin settings:
+```java
+public class MyPluginConfig {
+ public static class Plugin {
+ @PluginConfig(root = MyPluginConfig.class)
+ public static class MyPlugin {
+ public static boolean SOME_SETTING = false;
+ }
+ }
+}
+```
+Config key becomes: `plugin.myplugin.some_setting`
+
+#### Dependency Management
+
+**Plugin dependencies must use `provided` scope:**
+```xml
+<dependency>
+ <groupId>com.example</groupId>
+ <artifactId>target-library</artifactId>
+ <version>${version}</version>
+ <scope>provided</scope>
+</dependency>
+```
+
+**Agent core dependency policy:**
+- New dependencies in agent core are treated with extreme caution
+- Prefer using existing imported libraries already in the project
+- Prefer JDK standard libraries over third-party libraries
+- Plugins should rely on the target application's libraries (provided scope),
not bundle them
+
+### Tracing Concepts
+
+#### Span Types
+- **EntrySpan**: Service provider/endpoint (HTTP server, MQ consumer)
+- **LocalSpan**: Internal method (no remote calls)
+- **ExitSpan**: Client call (HTTP client, DB access, MQ producer)
+
+#### SpanLayer (required for EntrySpan/ExitSpan)
+- `DB`: Database access
+- `RPC_FRAMEWORK`: RPC calls (not ordinary HTTP)
+- `HTTP`: HTTP calls
+- `MQ`: Message queue
+- `UNKNOWN`: Default
+
+#### Context Propagation
+- **ContextCarrier**: Cross-process propagation (serialize to
headers/attachments)
+- **ContextSnapshot**: Cross-thread propagation (in-memory, no serialization)
+
+#### Required Span Attributes
+For EntrySpan and ExitSpan, always set:
+```java
+span.setComponent(ComponentsDefine.YOUR_COMPONENT);
+span.setLayer(SpanLayer.HTTP); // or DB, MQ, RPC_FRAMEWORK
+```
+
+#### Special Tags for OAP Analysis
+| Tag | Purpose |
+|-----|---------|
+| `http.status_code` | HTTP response code (integer) |
+| `db.type` | Database type (e.g., "sql", "redis") |
+| `db.statement` | SQL/query statement (enables slow query analysis) |
+| `cache.type`, `cache.op`, `cache.cmd`, `cache.key` | Cache metrics |
+| `mq.queue`, `mq.topic` | MQ metrics |
+
+### Meter Plugin APIs
+
+For collecting numeric metrics (alternative to tracing):
+```java
+// Counter
+Counter counter = MeterFactory.counter("metric_name")
+ .tag("key", "value")
+ .mode(Counter.Mode.INCREMENT)
+ .build();
+counter.increment(1d);
+
+// Gauge
+Gauge gauge = MeterFactory.gauge("metric_name", () -> getValue())
+ .tag("key", "value")
+ .build();
+
+// Histogram
+Histogram histogram = MeterFactory.histogram("metric_name")
+ .steps(Arrays.asList(1, 5, 10))
+ .build();
+histogram.addValue(3);
+```
+
+### Data Flow
+1. Agent attaches to JVM via `-javaagent` flag
+2. ByteBuddy transforms target classes at load time
+3. Interceptors collect span/trace data on method entry/exit
+4. Data is buffered via DataCarrier
+5. gRPC reporter sends data to OAP backend
+
+## Code Style & Conventions
+
+### Checkstyle Rules (enforced via `apm-checkstyle/checkStyle.xml`)
+
+**Prohibited patterns:**
+- No `System.out.println` - use proper logging
+- No `@author` tags - ASF projects don't use author annotations
+- No Chinese characters in source files
+- No tab characters (use 4 spaces)
+- No star imports (`import xxx.*`)
+- No unused or redundant imports
+
+**Required patterns:**
+- `@Override` annotation required for overridden methods
+- `equals()` and `hashCode()` must be overridden together
+- Apache 2.0 license header on all source files
+
+**Naming conventions:**
+- Constants/static variables: `UPPER_CASE_WITH_UNDERSCORES`
+- Package names: `org.apache.skywalking.apm.*` or
`test.apache.skywalking.apm.*`
+- Type names: `PascalCase`
+- Local variables/parameters/members: `camelCase`
+- Plugin directories: `{framework}-{version}-plugin`
+- Instrumentation classes: `*Instrumentation.java`
+- Interceptor classes: `*Interceptor.java`
+
+**File limits:**
+- Max file length: 3000 lines
+
+### Lombok Usage
+Use Lombok annotations for boilerplate code:
+- `@Getter`, `@Setter`, `@Data`
+- `@Builder`
+- `@Slf4j` for logging
+
+## Testing
+
+### Test Frameworks
+- JUnit 4.12 for unit tests
+- Mockito 5.0.0 for mocking
+
+### Test Categories
+
+**Unit Tests** (in each module's `src/test/java`)
+- Standard JUnit tests
+- Pattern: `*Test.java`
+
+**Plugin E2E Tests** (`test/plugin/scenarios/`)
+- 100+ test scenarios for plugin validation
+- Docker-based testing with actual frameworks
+- Pattern: `{framework}-{version}-scenario`
+
+**End-to-End Tests** (`test/e2e/`)
+- Full system integration testing
+
+### Running Tests
+```bash
+# Unit tests
+./mvnw test
+
+# Full verification including checkstyle
+./mvnw clean verify
+
+# Skip tests during build
+./mvnw package -Dmaven.test.skip=true
+```
+
+### Plugin Test Framework
+
+The plugin test framework verifies plugin functionality using Docker
containers with real services and a mock OAP backend.
+
+#### Environment Requirements
+- MacOS/Linux
+- JDK 8+
+- Docker & Docker Compose
+
+#### Test Case Structure
+
+**JVM-container (preferred):**
+```
+{scenario}-scenario/
+├── bin/
+│ └── startup.sh # JVM startup script (required)
+├── config/
+│ └── expectedData.yaml # Expected trace/meter/log data
+├── src/main/java/... # Test application code
+├── pom.xml
+├── configuration.yml # Test case configuration
+└── support-version.list # Supported versions (one per line)
+```
+
+**Tomcat-container:**
+```
+{scenario}-scenario/
+├── config/
+│ └── expectedData.yaml
+├── src/main/
+│ ├── java/...
+│ └── webapp/WEB-INF/web.xml
+├── pom.xml
+├── configuration.yml
+└── support-version.list
+```
+
+#### Key Configuration Files
+
+**configuration.yml:**
+```yaml
+type: jvm # or tomcat
+entryService: http://localhost:8080/case # Entry endpoint (GET)
+healthCheck: http://localhost:8080/health # Health check endpoint (HEAD)
+startScript: ./bin/startup.sh # JVM-container only
+runningMode: default #
default|with_optional|with_bootstrap
+withPlugins: apm-spring-annotation-plugin-*.jar # For optional/bootstrap modes
+environment:
+ - KEY=value
+dependencies: # External services
(docker-compose style)
+ mysql:
+ image: mysql:8.0
+ hostname: mysql
+ environment:
+ - MYSQL_ROOT_PASSWORD=root
+```
+
+**support-version.list:**
+```
+# One version per line, use # for comments
+# Only include ONE version per minor version (not all patch versions)
+4.3.6
+4.4.1
+4.5.0
+```
+
+**expectedData.yaml:**
+
+Trace and meter expectations are typically in separate scenarios.
+
+*For tracing plugins:*
+```yaml
+segmentItems:
+ - serviceName: your-scenario
+ segmentSize: ge 1 # Operators: eq, ge, gt, nq
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: /your/endpoint
+ parentSpanId: -1 # -1 for root span
+ spanId: 0
+ spanLayer: Http # Http, DB, RPC_FRAMEWORK, MQ,
CACHE, Unknown
+ spanType: Entry # Entry, Exit, Local
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 1
+ isError: false
+ peer: '' # Empty string for Entry/Local,
required for Exit
+ skipAnalysis: false
+ tags:
+ - {key: url, value: not null}
+ - {key: http.method, value: GET}
+ - {key: http.status_code, value: '200'}
+ logs: []
+ refs: [] # SegmentRefs for
cross-process/cross-thread
+```
+
+*For meter plugins:*
+```yaml
+meterItems:
+ - serviceName: your-scenario
+ meterSize: ge 1
+ meters:
+ - meterId:
+ name: test_counter
+ tags:
+ - {name: key1, value: value1} # Note: uses 'name' not 'key'
+ singleValue: gt 0 # For counter/gauge
+ - meterId:
+ name: test_histogram
+ tags:
+ - {name: key1, value: value1}
+ histogramBuckets: # For histogram
+ - 0.0
+ - 1.0
+ - 5.0
+ - 10.0
+```
+
+**startup.sh (JVM-container):**
+```bash
+#!/bin/bash
+home="$(cd "$(dirname $0)"; pwd)"
+# ${agent_opts} is REQUIRED - contains agent parameters
+java -jar ${agent_opts} ${home}/../libs/your-scenario.jar &
+```
+
+#### Running Plugin Tests Locally
+
+```bash
+# Run a specific scenario
+bash ./test/plugin/run.sh -f {scenario_name}
+
+# IMPORTANT: Rebuild agent if apm-sniffer code changed
+./mvnw clean package -DskipTests -pl apm-sniffer
+
+# Use generator to create new test case
+bash ./test/plugin/generator.sh
+```
+
+#### Adding Tests to CI
+
+Add scenario to the appropriate `.github/workflows/` file:
+- Use `python3 tools/select-group.py` to find the file with fewest cases
+- **JDK 8 tests**: `plugins-test.<n>.yaml`
+- **JDK 17 tests**: `plugins-jdk17-test.<n>.yaml`
+- **JDK 21 tests**: `plugins-jdk21-test.<n>.yaml`
+- **JDK 25 tests**: `plugins-jdk25-test.<n>.yaml`
+
+```yaml
+matrix:
+ case:
+ - your-scenario-scenario
+```
+
+#### Test Code Package Naming
+- Test code: `org.apache.skywalking.apm.testcase.*`
+- Code to be instrumented: `test.org.apache.skywalking.apm.testcase.*`
+
+## Git Submodules
+
+The project uses submodules for protocol definitions:
+- `apm-protocol/apm-network/src/main/proto` - skywalking-data-collect-protocol
+
+Always use `--recurse-submodules` when cloning or update submodules manually:
+```bash
+git submodule init && git submodule update
+```
+
+## IDE Setup (IntelliJ IDEA)
+
+1. Import as Maven project
+2. Run `./mvnw compile -Dmaven.test.skip=true` to generate protobuf sources
+3. Mark generated source folders:
+ - `*/target/generated-sources/protobuf/java`
+ - `*/target/generated-sources/protobuf/grpc-java`
+4. Enable annotation processing for Lombok
+
+## Key Files for Understanding the Codebase
+
+- `apm-sniffer/apm-agent/` - Agent entry point (premain)
+- `apm-sniffer/apm-agent-core/src/main/java/.../enhance/` - Instrumentation
engine
+- `apm-sniffer/apm-agent-core/src/main/java/.../plugin/` - Plugin loading
system
+- `apm-sniffer/apm-sdk-plugin/` - All standard plugins (reference
implementations)
+- `apm-sniffer/config/agent.config` - Default agent configuration
+
+## Common Development Tasks
+
+### Adding a New Plugin
+1. Create directory in
`apm-sniffer/apm-sdk-plugin/{framework}-{version}-plugin/`
+2. Implement instrumentation class using **V2 API** (e.g., extend
`ClassInstanceMethodsEnhancePluginDefineV2`)
+3. Implement interceptor class using **V2 API** (e.g., implement
`InstanceMethodsAroundInterceptorV2`)
+4. Register plugin in `skywalking-plugin.def` file
+5. Add test scenario in `test/plugin/scenarios/`
+
+### Adding an Optional Plugin
+1. Create in `apm-sniffer/optional-plugins/`
+2. Update documentation in
`docs/en/setup/service-agent/java-agent/Optional-plugins.md`
+
+### Modifying Agent Configuration
+1. Edit `apm-sniffer/config/agent.config`
+2. Update documentation if adding new options
+
+## Documentation
+
+- `docs/en/setup/service-agent/java-agent/` - Main agent documentation
+- `docs/en/setup/service-agent/java-agent/Plugin-list.md` - Complete plugin
list
+- `docs/en/setup/service-agent/java-agent/Optional-plugins.md` - Optional
plugins guide
+- `CHANGES.md` - Changelog (update when making changes)
+
+## Community
+
+- GitHub Issues: https://github.com/apache/skywalking-java/issues
+- Mailing List: [email protected]
+- Slack: #skywalking channel at Apache Slack
+
+## Submitting Pull Requests
+
+### Branch Strategy
+- **Never work directly on main branch**
+- Create a new branch for your changes
+
+### PR Template
+Follow `.github/PULL_REQUEST_TEMPLATE` based on change type:
+- **Bug fix**: Add unit test, explain bug cause and fix
+- **New plugin**: Add test case, component ID in OAP, logo in UI repo
+- **Performance improvement**: Add benchmark with results, link to
theory/discussion
+- **New feature**: Link design doc if non-trivial, update docs, add tests
+
+### PR Requirements
+- Follow Apache Code of Conduct
+- Include updated documentation for new features
+- Include tests for new functionality
+- Reference original issue (e.g., "Resolves #123")
+- Update `CHANGES.md` for user-facing changes
+- Pass all CI checks (checkstyle, tests, license headers)
+
+### PR Description
+- Bug fixes: Explain the bug and how it's fixed, add regression test
+- New features: Link to design doc if non-trivial, update docs, add tests
+- Do NOT add AI assistant as co-author
+
+## CI/CD
+
+GitHub Actions workflows:
+- **CI**: Multi-OS (Ubuntu, macOS, Windows), Multi-Java (8, 11, 17, 21, 25)
+- **Plugin Tests**: Parallel E2E tests for all plugins
+- **E2E Tests**: Full system integration
+- **Docker Publishing**: Multi-variant images
+
+## Tips for AI Assistants
+
+1. **Use V2 instrumentation API**: Always use V2 classes
(`ClassEnhancePluginDefineV2`, `InstanceMethodsAroundInterceptorV2`) for new
plugins; V1 is legacy
+2. **NEVER use `.class` references**: In instrumentation definitions, always
use string literals for class names (e.g., `byName("com.example.MyClass")` not
`byName(MyClass.class.getName())`)
+3. **Always set component and layer**: For EntrySpan and ExitSpan, always call
`setComponent()` and `setLayer()`
+4. **Prefer `byName` for class matching**: Avoid `byHierarchyMatch` unless
necessary (causes performance issues)
+5. **Use witness classes for version-specific plugins**: Implement
`witnessClasses()` or `witnessMethods()` to activate plugins only for specific
library versions
+6. **Always check submodules**: Protocol changes may require submodule updates
+7. **Generate sources first**: Run `mvnw compile` before analyzing generated
code
+8. **Respect checkstyle**: No System.out, no @author, no Chinese characters
+9. **Follow plugin patterns**: Use existing V2 plugins as templates
+10. **Use Lombok**: Prefer annotations over boilerplate code
+11. **Test both unit and E2E**: Different test patterns for different scopes
+12. **Plugin naming**: Follow `{framework}-{version}-plugin` convention
+13. **Shaded dependencies**: Core dependencies are shaded to avoid classpath
conflicts
+14. **Java version compatibility**: Agent core must maintain Java 8
compatibility, but individual plugins may target higher JDK versions (e.g.,
jdk-httpclient-plugin for JDK 11+, virtual-thread plugins for JDK 21+)
+15. **Bootstrap instrumentation**: Only use for JDK core classes, and only
when absolutely necessary
+16. **Register plugins**: Always add plugin definition to
`skywalking-plugin.def` file