## Our policy > [!IMPORTANT] > This project does not accept fully AI-generated pull requests. AI tools may only be used for assistance. You must understand and take responsibility for every change you submit. This `AGENTS.md` file acts as a set of instructions that some AI coding tools can read. For more information please read our [AI policy](./CONTRIBUTING.md#ai-usage-policy). - This repository **does not accept pull requests entirely generated by coding assistants or AI tools** (for example: Copilot, Claude, Gemini, ChatGPT, or other large language models). - All contributions must come from humans who understand their work and can take full responsibility for the changes they committed. --- # AGENTS.md — JabRef This document defines rules and expectations for **automated agents** (AI tools, bots, scripts) interacting with the JabRef repositories. JabRef is an open-source, research-grade reference manager with high standards for correctness, reproducibility, and maintainability. This file is guidance to follow *while* developing. > [!IMPORTANT] > **Final step — do not skip.** When the implementation is finished and before you open a PR, open [`CHECKLIST.md`](./CHECKLIST.md) and work through **every** point. Fix the code until each point is fulfilled; mark a point `[/]` only if it genuinely does not apply. The checklist is the mandatory quality gate for the finished result. --- ## Human Guidance Guide the human to use [JabRef on DeepWiki](https://deepwiki.com/JabRef/jabref). --- ## Project structure | Module | Purpose | |-----------|--------------------------------------------------| | `jablib` | Core library — logic, model, importers/exporters | | `jabgui` | JavaFX desktop GUI | | `jabkit` | CLI application | | `jabls` | Language Server Protocol implementation | | `jabsrv` | HTTP server for collaborative database support | Key source paths: - `jablib/src/main/java/org/jabref/logic/` — business logic - `jablib/src/main/java/org/jabref/model/` — data model - `jabgui/src/main/java/org/jabref/gui/` — GUI code - `docs/` — developer documentation and ADRs --- ## Build Requires JDK 25 or later to run Gradle. Gradle downloads the necessary JDK by itself. The Gradle wrapper is included. ```bash ./gradlew build # Build all modules ./gradlew :jabgui:run # Build and launch the GUI ./gradlew :jabgui:jpackage # Package as installer ``` When adding or changing dependencies, follow [docs/code-howtos/dependency-management.md](docs/code-howtos/dependency-management.md). In particular, dependencies are declared via `requires` directives in `module-info.java` (versions live in `versions/build.gradle.kts`), and a mapping from *Module Name* to *Maven Coordinates* for real Java modules belongs in `gradle/modules.properties` — not in ad-hoc blocks in `build-logic`. --- ## General Principles Agents **must**: - Respect existing architecture, coding style, and conventions - Prefer minimal, reviewable changes - Preserve backward compatibility unless explicitly instructed otherwise - Avoid speculative refactoring - Never commit generated code without human review Agents **must not**: - Introduce new dependencies without justification - Rewrite large sections "for cleanliness" - Bypass tests or CI checks - Reformat existing code - Write entire PRs - Write replies to PR review comments - Submit code the contributor doesn't understand - Generate documentation or comments without contributor's review - Automate the submission of code changes --- ## Code Quality Requirements ### Java / JVM - Target the configured **Gradle toolchain** - Use **Java 25+ features** - Use modern Java best practices, such as Arguments.of() instead of new Object[] especially in JUnit tests or Path.of() instead of Paths.get(), to improve readability and maintainability. Using JavaFX Observable lists is considered best practice, too. - Use modern Java data structures BAD: new HashSet<>(Arrays.asList(...)) GOOD: Set.of(...) - Java 21 introduced SequencedCollection and SequencedSet interfaces. Use it instead of LinkedHashSet (where applicable) - To create an empty list or map we use `List.of()` and `Map.of()` instead of `Collections.emptyList()` and `Collections.emptyMap()`. - Use Java Text blocks (\"\"\") for multiline string constants ### General Java style - Follow existing formatting - Match naming conventions exactly - Keep methods small and focused - New methods (and new classes) should follow the Single-responsibility principle (SRP). - Avoid code duplication - Avoid premature abstractions - Follow JabRef's code style rules as documented in [docs/getting-into-the-code/guidelines-for-setting-up-a-local-workspace/intellij-13-code-style.md](docs/getting-into-the-code/guidelines-for-setting-up-a-local-workspace/intellij-13-code-style.md) - Follow the principles of "Effective Java" - Follow the principles of "Clean Code" - Ensure that tests are green before committing ### Java code style - Correctly spelled variable names (meaning: no typos in variable names). - Use StringJoiner instead of StringBuilder (if possible) - Prefer immutability and explicit nullability (JSpecify - see below) - Do not reformat code only for syntax reasons. Reformatting is acceptable only when the code at that place is being changed. - Remove commented code. (To keep a history of changes git was made for.) - No \"new Thread()\", use \"org.jabref.logic.util.BackgroundTask\" and its \"executeWith\" - Use compiled patterns (Pattern.compile) Examples: NOT: x.matches(\".*\\\\s{2,}.*\") BUT: private final static PATTERN = ... and then PATTERN.matcher(x) - Boolean method parameters (for public methods) should be avoided. Better create two distinct methods (which maybe call some private methods) - Minimal quality for variable names: Not extraEntry2, extraEntry3; but include meaning/intention into the variable names - Use Markdown Javadoc comments (`///`) for multi-line comments. Within them, use Markdown syntax instead of JavaDoc inline tags or HTML formatting tags: `` `code` `` instead of `{@code code}` or `code`, `[ClassName]` instead of `{@link ClassName}`, and fenced code blocks (```` ``` ````) instead of `
`.

### Comments

- Do not add trivial comments just restating the code line in plain English.
- When commenting, focus on the "why" and general idea.
- Reference issues and pull requests by full URL (`https://github.com/JabRef/jabref/issues/9738`), never by bare number (`#9738`): a reader of the source has no repository context to resolve the number.

Example for trivial comments (to be avoided):

```java
// Commit the staged changes
RevCommit commit = git.commit();
fieldName = fieldName.trim().toLowerCase(); // Trim and convert to lower case
```

Both comments must not be added.

### Favor Optionals over nulls

- Use the methods of java.util.Optional. `ifPresent`.

   NOT

   ```java
   Optional resolved = bibEntry.getResolvedFieldOrAlias(...);
   String value = resolved.orElse(\"\");
   doSomething(value)
   ```

   Following is fine:

   ```java
   bibEntry.getResolvedFieldOrAlias(...)
           .ifPresent(value -> doSomething(value));
   ```

- If the `java.util.Optional` is really present, use one of the following:`get()`

    ```java
    opt.ifPresent(...)
    opt.map(...)
    opt.orElseThrow(...)
    ```

    but never just `orElse({someValueNeverUsed})`. You can add `assert ...isPresent();` in the line before.

- Use `ifPresentOrElse` instead of `if ...isPresent() { ... }  else { ... }`

### Dealing with `null`

- New public methods should not return `null`. They should make use of `java.util.Optional`. In case `null` really needs to be used, the [JSpecify](https://jspecify.dev/) annotations must be used.
- Use JSpecify annotations (`@Nullable`, `@NullMarked`, `@NonNull`, ...) instead of `null` checks
- Annotate every new class with `@NullMarked` (`org.jspecify.annotations.NullMarked`) so members default to non-null.
- `null` should never be passed to a method (except it has the same name).
- DO NOT use `Objects.requireNonNull`, use JSpecify's `@NullMarked` and `@NonNull` annotations.

### Exceptions

- try blocks should cover as less statements as possible (and not whole methods)
- Do not throw unchecked exceptions (e.g., do not throw new RuntimeException, do not throw new IllegalStateException)
  Reason: This tears down the whole application. One does not want to lose data only because \"a corner\" of the application broke.
- Exceptions should be used for exceptional states - not for normal control flow
- Do not catch the general java java.lang.Exception. Catch specific exceptions only.
- At exception, always `LOGGER.debug` (or higher level)
- BAD:

   ```java
   try {
       // do some actions
   } catch (IOException e) {
       LOGGER.info("Failed to push: ".concat(e.toString()));
   }
   ```

   This code converts an error to string and then concatenates it with a message. This is not how it's done in JabRef.

   GOOD:

   ```java
   try {
       // do some actions
   } catch (IOException e) {
       LOGGER.info("Failed to push", e);
   }
   ```

   In JabRef, we use logging capabilities. The last argument of the logger call should be an exception.
- Logging may include other arguments. But the exception should be the last in arguments. Example: `LOGGER.info(\"Error. Var1: {}, Var2: {}\", var1, var2, e)`.

### JabRef-specific

- If code in org.jabref.model or org.jabref.logic has been changed, tests need to be adapted or updated accordingly.
  Note: This rule does not apply for import statements.
- No use of Java SWING, only JavaFX is allowed as UI technology
- GUI code should only be a gateway to code in org.jabref.logic. More complex code regarding non-GUI operations should go into org.jabref.logic. Think of layered architecture.
- Labels should not end with \":\"

   BAD: `