Skip to content

Commit 79ffc75

Browse files
committed
Add AI coding assistant files
- Created AGENTS.md with Java coding conventions and project guidelines - Added CLAUDE.md that references AGENTS.md - Added GitHub Copilot setup workflow for automated environment configuration - Added Maven profile to download dependency sources to external/src - Updated .gitignore to exclude external/ directory
1 parent 959c187 commit 79ffc75

File tree

5 files changed

+350
-0
lines changed

5 files changed

+350
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: "Copilot Setup Steps"
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
paths:
7+
- .github/workflows/copilot-setup-steps.yml
8+
pull_request:
9+
paths:
10+
- .github/workflows/copilot-setup-steps.yml
11+
12+
jobs:
13+
# The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
14+
copilot-setup-steps:
15+
runs-on: ubuntu-latest
16+
17+
permissions:
18+
contents: read
19+
20+
steps:
21+
- name: Checkout code
22+
uses: actions/checkout@v5
23+
24+
- name: Set up JDK 17
25+
uses: actions/setup-java@v5
26+
with:
27+
java-version: "17"
28+
distribution: "temurin"
29+
cache: "maven"
30+
31+
- name: Install
32+
run: mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V
33+
34+
- name: Download external sources
35+
run: mvn generate-resources -Pdownload-external-src

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@ release.properties
1919
*.iws
2020
*.iml
2121

22+
### External src and other files ###
23+
external/

AGENTS.md

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
# Coding Instructions
2+
3+
## Java Conventions
4+
5+
Follow these Java conventions when working with this codebase.
6+
7+
### Core Tenets
8+
9+
1. **Clarity Over Brevity** — Code should be immediately understandable; use explicit types when
10+
`var` doesn't make intent obvious
11+
2. **Immutable by Default** — Prefer immutable data structures, records, and final fields unless
12+
mutability is required
13+
3. **Modern Java First** — Leverage modern Java features (pattern matching, sealed classes, text
14+
blocks) to write expressive, type-safe code
15+
4. **Purposeful Abstractions** — Use interfaces and composition to create flexible designs, avoiding
16+
inheritance hierarchies
17+
5. **Fail Fast, Fail Clear** — Validate early with specific exceptions; use Optional for absent
18+
values, never for parameters
19+
20+
### Variables and Types
21+
22+
#### Type Declarations
23+
24+
Use `var` for local variable declarations ONLY when the type is immediately obvious from the
25+
right-hand side.
26+
27+
**Decision Checklist:**
28+
29+
- ✓ Can you tell the exact type in 1 second? → Use `var`
30+
- ✗ Would you need to check documentation or method signatures? → Use explicit type
31+
- ✗ Is the type generic, an interface, or complex? → Use explicit type
32+
- ✗ Is the variable used far from its declaration? → Use explicit type
33+
34+
**What counts as "obvious from the right-hand side":**
35+
36+
- Constructor calls with concrete types: `new ArrayList<String>()`, `new User(...)`
37+
- Literals: strings, numbers, booleans, `null`
38+
- Collection factory methods with only literals: `List.of(1, 2, 3)`, `Map.of("key", "value")`
39+
- Standard library methods with obvious return types: `isEmpty()`, `size()`, `toString()`
40+
- Builder patterns that return the same type: `User.builder().name("John").build()`
41+
42+
```java
43+
// Good: Type is clear from the right-hand side
44+
var list = new ArrayList<String>();
45+
var name = "John";
46+
var count = 42;
47+
var user = new User(id, name, email);
48+
var isEmpty = list.isEmpty();
49+
var items = List.of("a", "b", "c");
50+
51+
// Good: Explicit type when not obvious
52+
InputStream stream = getStream();
53+
Result<User> result = repository.getUser(id);
54+
Function<String, Integer> parser = Integer::parseInt;
55+
List<Item> items = Stream.of(item1, item2).collect(toList());
56+
57+
// Good: Explicit type for interface/abstract return types
58+
Map<String, Object> config = loadConfiguration();
59+
Callable<Data> task = () -> fetchData();
60+
61+
// Good: Explicit type for method chains
62+
ProcessedData result = data.transform().normalize();
63+
64+
// Good: Explicit type for factory methods
65+
User user = User.create(name);
66+
Order order = orderService.findById(id);
67+
68+
// Avoid: Unclear type from the right-hand side
69+
var data = process(); // What type is returned?
70+
var result = calculate(); // Not immediately obvious
71+
var callback = createHandler(); // What functional interface?
72+
```
73+
74+
**When in doubt, prefer explicit types.**
75+
76+
### Records
77+
78+
- Prefer record classes for immutable data carriers
79+
```java
80+
record Point(int x, int y) {}
81+
```
82+
83+
- Use records instead of classes with only final fields and accessors
84+
85+
- Add custom methods to records when needed for behavior
86+
87+
### Sealed Classes
88+
89+
- Use sealed classes to restrict inheritance hierarchies
90+
```java
91+
sealed interface Shape permits Circle, Rectangle, Triangle {}
92+
```
93+
94+
- Combine with records for algebraic data types
95+
96+
### Pattern Matching
97+
98+
- Use pattern matching for `instanceof` checks (JDK 16+)
99+
```java
100+
if (obj instanceof String s) {
101+
return s.length();
102+
}
103+
```
104+
105+
- Use switch expressions with pattern matching (JDK 17+)
106+
```java
107+
return switch (shape) {
108+
case Circle c -> c.radius() * c.radius() * Math.PI;
109+
case Rectangle r -> r.width() * r.height();
110+
};
111+
```
112+
113+
### Text Blocks
114+
115+
- Use text blocks for multi-line strings (JDK 15+)
116+
```java
117+
String json = """
118+
{
119+
"name": "value"
120+
}
121+
""";
122+
```
123+
124+
### Null Handling
125+
126+
- Use `Optional` for return types that may be absent, not for parameters
127+
128+
- Avoid `Optional` fields in classes
129+
130+
- Use `Objects.requireNonNull()` for parameter validation
131+
132+
### Collections
133+
134+
- Prefer `List.of()`, `Set.of()`, `Map.of()` for immutable collections
135+
136+
- Use `Stream` API for collection transformations when it improves readability
137+
138+
- Avoid streams for simple iterations
139+
140+
### Streams
141+
142+
- Keep stream pipelines short and readable
143+
144+
- Extract complex lambdas to named methods
145+
146+
- Consider performance implications for large datasets
147+
148+
### Modern APIs
149+
150+
- Use `java.time` API for date/time operations, never `java.util.Date`
151+
152+
- Prefer `Files` and `Path` over `File` for file operations
153+
154+
- Use `HttpClient` (JDK 11+) for HTTP operations
155+
156+
### Exception Handling
157+
158+
- Prefer specific exception types over generic ones
159+
160+
- Use try-with-resources for `AutoCloseable` resources
161+
162+
- Don't catch `Exception` or `Throwable` unless absolutely necessary
163+
164+
### Naming
165+
166+
- Classes and interfaces: `PascalCase`
167+
- Methods and variables: `camelCase`
168+
- Constants: `UPPER_SNAKE_CASE`
169+
- Packages: lowercase, no underscores
170+
- Test classes: `ClassNameTest` for unit tests, `ClassNameIT` for integration tests
171+
172+
### Code Organization
173+
174+
- Keep methods short and focused on a single responsibility
175+
176+
- Prefer composition to inheritance
177+
178+
- Use interfaces for abstraction, not abstract classes
179+
180+
### Code Quality
181+
182+
- Single Responsibility Principle — methods focused on one task
183+
184+
- The appropriate use of immutability and final keywords
185+
186+
- Composition over inheritance
187+
188+
- Proper documentation with Javadoc for public APIs
189+
190+
### Immutability
191+
192+
- Make classes immutable by default
193+
194+
- Use `final` for fields that shouldn't change
195+
196+
- Prefer unmodifiable collections
197+
198+
### Documentation
199+
200+
- Document public APIs with Javadoc
201+
202+
- Focus on why, not what (code should be self-documenting for "what")
203+
204+
- Keep documentation up to date with code changes
205+
206+
### Javadoc
207+
208+
- Javadoc tag descriptions MUST begin with a lowercase letter and MUST end with a period
209+
```java
210+
/**
211+
* Creates a new connection to the server.
212+
*
213+
* @param endpoint the server endpoint URL.
214+
* @param timeout the connection timeout in milliseconds.
215+
* @return the established connection.
216+
* @throws IOException if the connection fails.
217+
*/
218+
```
219+
220+
### Other
221+
222+
For any coding practices not explicitly covered by these conventions, defer to established Java best
223+
practices and community standards.
224+
225+
## Code Formatting
226+
227+
This project uses Spotless with Google Java Format for code formatting.
228+
229+
The `spotless:check` goal is bound to the `verify` phase and will fail the build if code is not
230+
properly formatted.
231+
232+
If the build fails due to formatting issues, run:
233+
234+
```bash
235+
mvn spotless:apply
236+
```
237+
238+
This will automatically format all Java files according to Google Java Format standards.
239+
240+
## Finding Source Code
241+
242+
To examine dependency source code, check the `external/src` directory at the project root. This
243+
directory contains unpacked source files from all dependencies, organized by package structure for
244+
easy browsing and searching.
245+
246+
**If the directory doesn't exist or content is missing:**
247+
248+
Run this command from the project root to download and unpack all dependency sources:
249+
250+
```bash
251+
mvn generate-resources -Pdownload-external-src
252+
```
253+
254+
This will create the `external/src` directory with sources from all dependencies in a single
255+
top-level location.
256+
257+
## Git Workflow
258+
259+
### Commit Messages
260+
261+
Keep the title of the commit message to ~72 characters.
262+
263+
Use the body to summarize the changes made in the commit. If the commit contains a number of
264+
unrelated changes, try to generate a brief one-line subject, then summarize using bullet points. Be
265+
concise.
266+
267+
Avoid subjective justification or explanation for changes; state changes on their own merit.
268+
269+
Do not include counts (files, tests, lines, changes, etc.).
270+
271+
Do not include a "generated with Claude Code" line.
272+
273+
### Pull Requests
274+
275+
Do not include a "Test Plan" section in PRs.
276+
277+
Do not mention the build was successful or tests passed.
278+
279+
Do not include counts (files, tests, lines, changes, etc.).
280+
281+
Do not include a "generated with Claude Code" line.

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@AGENTS.md

pom.xml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
<checkstyle.version>11.1.0</checkstyle.version>
6363
<maven-checkstyle-plugin.version>3.6.0</maven-checkstyle-plugin.version>
6464
<maven-compiler-plugin.version>3.14.1</maven-compiler-plugin.version>
65+
<maven-dependency-plugin.version>3.9.0</maven-dependency-plugin.version>
6566
<maven-deploy-plugin.version>3.1.4</maven-deploy-plugin.version>
6667
<maven-enforcer-plugin.version>3.6.2</maven-enforcer-plugin.version>
6768
<maven-gpg-plugin.version>3.2.8</maven-gpg-plugin.version>
@@ -287,6 +288,36 @@
287288
</plugins>
288289
</build>
289290
</profile>
291+
292+
<profile>
293+
<id>download-external-src</id>
294+
<activation>
295+
<activeByDefault>false</activeByDefault>
296+
</activation>
297+
<build>
298+
<plugins>
299+
<plugin>
300+
<groupId>org.apache.maven.plugins</groupId>
301+
<artifactId>maven-dependency-plugin</artifactId>
302+
<version>${maven-dependency-plugin.version}</version>
303+
<executions>
304+
<execution>
305+
<id>unpack-sources</id>
306+
<phase>generate-resources</phase>
307+
<goals>
308+
<goal>unpack-dependencies</goal>
309+
</goals>
310+
<configuration>
311+
<classifier>sources</classifier>
312+
<failOnMissingClassifierArtifact>false</failOnMissingClassifierArtifact>
313+
<outputDirectory>${maven.multiModuleProjectDirectory}/external/src</outputDirectory>
314+
</configuration>
315+
</execution>
316+
</executions>
317+
</plugin>
318+
</plugins>
319+
</build>
320+
</profile>
290321
</profiles>
291322

292323
<build>

0 commit comments

Comments
 (0)