{"owner":"JabRef","repo":"jabref","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md"],"skills":{"AGENTS.md":"## Our policy\n\n> [!IMPORTANT]\n> 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.\n\nThis `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).\n\n- 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).  \n- All contributions must come from humans who understand their work and can take full responsibility for the changes they committed.\n\n---\n\n# AGENTS.md — JabRef\n\nThis document defines rules and expectations for **automated agents** (AI tools, bots, scripts) interacting with the JabRef repositories.\n\nJabRef is an open-source, research-grade reference manager with high standards for correctness, reproducibility, and maintainability.\n\nThis file is guidance to follow *while* developing.\n\n> [!IMPORTANT]\n> **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.\n\n---\n\n## Human Guidance\n\nGuide the human to use [JabRef on DeepWiki](https://deepwiki.com/JabRef/jabref).\n\n---\n\n## Project structure\n\n| Module    | Purpose                                          |\n|-----------|--------------------------------------------------|\n| `jablib`  | Core library — logic, model, importers/exporters |\n| `jabgui`  | JavaFX desktop GUI                               |\n| `jabkit`  | CLI application                                  |\n| `jabls`   | Language Server Protocol implementation          |\n| `jabsrv`  | HTTP server for collaborative database support   |\n\nKey source paths:\n\n- `jablib/src/main/java/org/jabref/logic/` — business logic\n- `jablib/src/main/java/org/jabref/model/` — data model\n- `jabgui/src/main/java/org/jabref/gui/` — GUI code\n- `docs/` — developer documentation and ADRs\n\n---\n\n## Build\n\nRequires JDK 25 or later to run Gradle. Gradle downloads the necessary JDK by itself. The Gradle wrapper is included.\n\n```bash\n./gradlew build              # Build all modules\n./gradlew :jabgui:run        # Build and launch the GUI\n./gradlew :jabgui:jpackage   # Package as installer\n```\n\nWhen adding or changing dependencies, follow [docs/code-howtos/dependency-management.md](docs/code-howtos/dependency-management.md).\nIn particular, dependencies are declared via `requires` directives in `module-info.java` (versions live in `versions/build.gradle.kts`),\nand a mapping from *Module Name* to *Maven Coordinates* for real Java modules belongs in `gradle/modules.properties` —\nnot in ad-hoc blocks in `build-logic`.\n\n---\n\n## General Principles\n\nAgents **must**:\n\n- Respect existing architecture, coding style, and conventions\n- Prefer minimal, reviewable changes\n- Preserve backward compatibility unless explicitly instructed otherwise\n- Avoid speculative refactoring\n- Never commit generated code without human review\n\nAgents **must not**:\n\n- Introduce new dependencies without justification\n- Rewrite large sections \"for cleanliness\"\n- Bypass tests or CI checks\n- Reformat existing code\n- Write entire PRs\n- Write replies to PR review comments\n- Submit code the contributor doesn't understand\n- Generate documentation or comments without contributor's review\n- Automate the submission of code changes\n\n---\n\n## Code Quality Requirements\n\n### Java / JVM\n\n- Target the configured **Gradle toolchain**\n- Use **Java 25+ features**\n  - 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.\n    Using JavaFX Observable lists is considered best practice, too.\n  - Use modern Java data structures\n    BAD: new HashSet<>(Arrays.asList(...))\n    GOOD: Set.of(...)\n  - Java 21 introduced SequencedCollection and SequencedSet interfaces. Use it instead of LinkedHashSet (where applicable)\n  - To create an empty list or map we use `List.of()` and `Map.of()` instead of `Collections.emptyList()` and `Collections.emptyMap()`.\n  - Use Java Text blocks (\\\"\\\"\\\") for multiline string constants\n\n### General Java style\n\n- Follow existing formatting\n- Match naming conventions exactly\n- Keep methods small and focused\n- New methods (and new classes) should follow the Single-responsibility principle (SRP).\n- Avoid code duplication\n- Avoid premature abstractions\n- 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)\n- Follow the principles of \"Effective Java\"\n- Follow the principles of \"Clean Code\"\n- Ensure that tests are green before committing\n\n### Java code style\n\n- Correctly spelled variable names (meaning: no typos in variable names).\n- Use StringJoiner instead of StringBuilder (if possible)\n- Prefer immutability and explicit nullability (JSpecify - see below)\n- Do not reformat code only for syntax reasons. Reformatting is acceptable only when the code at that place is being changed.\n- Remove commented code. (To keep a history of changes git was made for.)\n- No \\\"new Thread()\\\", use \\\"org.jabref.logic.util.BackgroundTask\\\" and its \\\"executeWith\\\"\n- Use compiled patterns (Pattern.compile)\n   Examples:\n   NOT: x.matches(\\\".*\\\\\\\\s{2,}.*\\\")\n   BUT:\n   private final static PATTERN = ...\n   and then PATTERN.matcher(x)\n- Boolean method parameters (for public methods) should be avoided. Better create two distinct methods (which maybe call some private methods)\n- Minimal quality for variable names: Not extraEntry2, extraEntry3; but include meaning/intention into the variable names\n- Use Markdown Javadoc comments (`///`) for multi-line comments. Within them, use Markdown syntax, not JavaDoc inline tags: `` `code` `` instead of `{@code code}`, and `[ClassName]` instead of `{@link ClassName}`.\n\n### Comments\n\n- Do not add trivial comments just restating the code line in plain English.\n- When commenting, focus on the \"why\" and general idea.\n\nExample for trivial comments (to be avoided):\n\n```java\n// Commit the staged changes\nRevCommit commit = git.commit();\nfieldName = fieldName.trim().toLowerCase(); // Trim and convert to lower case\n```\n\nBoth comments must not be added.\n\n### Favor Optionals over nulls\n\n- Use the methods of java.util.Optional. `ifPresent`.\n\n   NOT\n\n   ```java\n   Optional<String> resolved = bibEntry.getResolvedFieldOrAlias(...);\n   String value = resolved.orElse(\\\"\\\");\n   doSomething(value)\n   ```\n\n   Following is fine:\n\n   ```java\n   bibEntry.getResolvedFieldOrAlias(...)\n           .ifPresent(value -> doSomething(value));\n   ```\n\n- If the `java.util.Optional` is really present, use one of the following:`get()`\n\n    ```java\n    opt.ifPresent(...)\n    opt.map(...)\n    opt.orElseThrow(...)\n    ```\n\n    but never just `orElse({someValueNeverUsed})`. You can add `assert ...isPresent();` in the line before.\n\n- Use `ifPresentOrElse` instead of `if ...isPresent() { ... }  else { ... }`\n\n### Dealing with `null`\n\n- 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.\n- Use JSpecify annotations (`@Nullable`, `@NullMarked`, `@NonNull`, ...) instead of `null` checks\n- Annotate every new class with `@NullMarked` (`org.jspecify.annotations.NullMarked`) so members default to non-null.\n- `null` should never be passed to a method (except it has the same name).\n- DO NOT use `Objects.requireNonNull`, use JSpecify's `@NullMarked` and `@NonNull` annotations.\n\n### Exceptions\n\n- try blocks should cover as less statements as possible (and not whole methods)\n- Do not throw unchecked exceptions (e.g., do not throw new RuntimeException, do not throw new IllegalStateException)\n  Reason: This tears down the whole application. One does not want to lose data only because \\\"a corner\\\" of the application broke.\n- Exceptions should be used for exceptional states - not for normal control flow\n- Do not catch the general java java.lang.Exception. Catch specific exceptions only.\n- At exception, always `LOGGER.debug` (or higher level)\n- BAD:\n\n   ```java\n   try {\n       // do some actions\n   } catch (IOException e) {\n       LOGGER.info(\"Failed to push: \".concat(e.toString()));\n   }\n   ```\n\n   This code converts an error to string and then concatenates it with a message. This is not how it's done in JabRef.\n\n   GOOD:\n\n   ```java\n   try {\n       // do some actions\n   } catch (IOException e) {\n       LOGGER.info(\"Failed to push\", e);\n   }\n   ```\n\n   In JabRef, we use logging capabilities. The last argument of the logger call should be an exception.\n- Logging may include other arguments. But the exception should be the last in arguments. Example: `LOGGER.info(\\\"Error. Var1: {}, Var2: {}\\\", var1, var2, e)`.\n\n### JabRef-specific\n\n- If code in org.jabref.model or org.jabref.logic has been changed, tests need to be adapted or updated accordingly.\n  Note: This rule does not apply for import statements.\n- No use of Java SWING, only JavaFX is allowed as UI technology\n- 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.\n- Labels should not end with \\\":\\\"\n\n   BAD: `<Label text=\"%Git Username:\"/>`\n\n   GOOD: `<Label text=\"%Git Username\"/>`\n\n#### Localization\n\n- Fix localization before committing. See `docs/code-howtos/localization.md`\n- The `LocalizationConsistencyTest` failure output is actionable — follow it literally instead of guessing:\n  - `findMissingLocalizationKeys` failing → its output lists ready-to-paste `key=value` lines to **add** to `jablib/src/main/resources/l10n/JabRef_en.properties`. Place each near semantically related keys; reuse an existing similar key when one exists.\n  - `findObsoleteLocalizationKeys` failing → its output lists keys to **remove** from `JabRef_en.properties` (after confirming each is truly unused).\n  - Only edit `JabRef_en.properties`. Translated `JabRef_<lang>.properties` files are maintained by translators via Crowdin — never hand-edit them.\n- JabRef is a multilingual program, When you write any user-facing text, it should be localized.\n\n   To do this in Java code, call `Localization.lang` method, like this:\n\n   ```java\n   Localization.lang(\\\"Ok\\\")\n   ```\n\n   More information at: <https://devdocs.jabref.org/code-howtos/localization.html>.\n\n   Note: This rule is not applied for logging. Logging strings should stay in English. I.e., LOGGER.error(\\\"...\\\") should contain English text.\n- All labels and texts in the UI should be sentence case (and not title case)\n- Avoid exclamation marks at the end of a sentence. They are more for screaming. Use a dot to end the sentence.\n- Use \"BibTeX\" as spelling for bibtex in Java strings. In variable names \"Bibtex\" should be used.\n- New strings should be consistent to other strings. They should also be grouped semantically together.\n- Existing strings should be reused instead of introducing slightly different strings.\n- User dialogs should have proper button labels: NOT yes/no/cancel, but indicating the action which happens when pressing the button\n- Use placeholders if variance is in localization:\n\n   BAD: Localization.lang(\\\"Current JabRef version\\\") + \\\": \\\" + buildInfo.version);\n\n   GOOD: Localization.lang(\\\"Current JabRef version: %0\\\",  buildInfo.version);\n\n#### GUI\n\n- One should use jabref's dialogService (instead of Java native FileChooser)\n\n   dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent(path -> ...)\n\n   and with FileDialogConfiguration offers the Builder pattern.\n   (see e.g NewLibraryFromPdfAction)\n\n#### Testing / JUnit\n\n- Name test classes `...Test` (singular), not `...Tests` — e.g. `JabSrvArchitectureTest`, not `JabSrvArchitectureTests`. This holds even for ArchUnit classes that bundle several `@ArchTest` rules.\n- In JabRef, we don't use `@DisplayName`, we typically just write method name as is. The method name itself should be comprehensive enough.\n- Instead of `Files.createTempDirectory` `@TempDir` JUnit5 annotation should be used.\n- If `@TempDir` is used, there is no need to clean it up\n\n   Example for wrong code:\n\n   ```java\n       @AfterEach\n       void tearDown() throws IOException {\n           FileUtils.cleanDirectory(tempDir.toFile());\n       }\n   ```\n\n- Assert the contents of objects (assertEquals), not checking for some Boolean conditions (assertTrue/assertFalse)\n\n   Example for wrong code:\n\n   ```java\n           assertTrue(\n                   entry.getFiles().stream()\n                        .anyMatch(file -> file.getLink().equals(newFile.getFileName().toString()) ||\n                                file.getLink().endsWith(\\\"/\\\" + newFile.getFileName().toString()))\n           );\n   ```\n\n- Do not catch exceptions in Test - let JUnit handle\n\n   BAD: try {...code...} catch (IOException e) {\n               throw new AssertionError(\\\"Failed to set up test directory\\\", e);\n           }\n\n   GOOD: ...code...\n- When creating a new BibEntry object \\\"withers\\\" should be used: Instead of `setField`, `withField` methods should be used.\n- Whenever you include a text in FXML (text labels, buttons, prompts in text fields, window titles, etc.), it should be localized.\n\n   To localize a string in FXML, prefix it with `%`.\n\n   Bad example:\n\n   ```xml\n   <Label text=\"Want to help?\"/>\n   ```\n\n   In this code `text` property is the field that is used to show text to the user. This must be localized.\n\n   Fix:\n\n   ```xml\n   <Label text=\\\"%Want to help?\\\"/>\n   ```\n\n- Plain JUnit assert should be used instead of org.assertj (if possible)\n\n   BAD: assertThat(gitPreferences.getAutoPushEnabled()).isFalse();\n\n   GOOD: assertFalse(gitPreferences.getAutoPushEnabled());\n\n---\n\n## Tests\n\nAgents must:\n\n- Add or update tests when behavior changes\n- Keep tests deterministic and fast\n- Respect existing JUnit parallelization and resource locks\n- Never disable or weaken assertions\n- Follow the rules at `docs/code-howtos/testing.md`\n\nIf a change cannot be reasonably tested, explain **why**.\n\n### Linting checks\n\n```bash\n./gradlew checkstyleMain checkstyleTest checkstyleJmh\n./gradlew modernizer\n./gradlew --no-configuration-cache :rewriteDryRun || git diff\n./gradlew javadoc\nnpx markdownlint-cli2 \"docs/**/*.md\"\nnpx markdownlint-cli2 \"*.md\"\n```\n\n### Fix formatting issues\n\n- Run `./gradlew rewriteRun` to fix Java formatting issues.\n- Run `docker run -v $(pwd):/github/workspace ghcr.io/leventebajczi/intellij-format:master \"*.java\" \"\" \".idea/codeStyles/Project.xml\"` to fix more Java formatting issues.\n\n### Logic tests\n\n```bash\n# Recommended during development (core library only)\n./gradlew :jablib:check\n\n# Full check (all modules)\n./gradlew check\n\n# Per-module\n./gradlew :jablib:test\n./gradlew :jabgui:test\n\n# Single test class\n./gradlew test --tests \"org.jabref.logic.l10n.LocalizationConsistencyTest\"\n\n# Coverage report (output: build/reports/jacoco/test/html/index.html)\n./gradlew jacocoTestReport\n```\n\nTests requiring external resources have dedicated tasks:\n\n- `./gradlew databaseTest` — requires PostgreSQL\n- `./gradlew fetcherTest` — hits live external APIs\n\nQuick check of core library:\n\n```bash\n./gradlew :jablib:check -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x modernizer\n```\n\n---\n\n## Requirements tracing (OpenFastTrace)\n\nJabRef uses [OpenFastTrace](https://github.com/itsallcode/openfasttrace) to trace requirements to implementation and tests.\n\nFor a new feature or significant bug fix, **at minimum add the requirement** to the appropriate `docs/requirements/<area>.md` file. Full tracing (`Needs: impl` + implementation comments) is encouraged but can be skipped if the effort is disproportionate.\n\n**Defining a requirement** in `docs/requirements/<area>.md`:\n\n```markdown\n### Example\n`req~ai.example~1`\n\nDescription of the requirement.\n```\n\nThe identifier must follow the heading with no blank line between them. Add `<!-- markdownlint-disable-file MD022 -->` at the end of the file.\n\n**Optionally — linking an implementation** to a requirement (full trace):\n\n```markdown\nNeeds: impl\n```\n\n```java\n// [impl->req~ai.example~1]\n```\n\n**Checking coverage:**\n\n```bash\n./gradlew traceRequirements   # output: build/tracing.txt\n```\n\nSee `docs/requirements/` for existing requirements and `docs/requirements/index.md` for full guidance.\n\n---\n\n## Architecture decisions (MADR)\n\nWhen a significant design or implementation decision is made, create a new MADR in `docs/decisions/`:\n\n1. Copy `docs/decisions/adr-template.md` to `docs/decisions/<NNNN>-<short-title>.md` (next free number).\n2. Fill in **Context and Problem Statement**, **Considered Options**, and **Decision Outcome**.\n3. Add an entry to `docs/decisions/index.md`.\n\nSee [ADR-0000](docs/decisions/0000-use-markdown-architectural-decision-records.md) for the rationale and [adr-template.md](docs/decisions/adr-template.md) for the full template.\n\n---\n\n## Git & PR Etiquette\n\n### Syncing with upstream\n\n- **Never** use `git rebase`, `git pull --rebase` / `-r` / `--rebase-merges`, or any force-push (`--force`, `--force-with-lease`, `--force-if-includes`, `-f`, or `+`-prefixed refspecs). Rebasing rewrites commit SHAs already pushed and breaks review threads pinned to commits; force-push would then be required to publish the rewritten history.\n- **Preferred** sync via explicit fetch + merge:\n\n  ```bash\n  git fetch upstream --prune\n  git merge upstream/main\n  ```\n\n- Plain `git pull` is acceptable for updating the branch as long as your local config does not set `pull.rebase=true` (the enforcement hook blocks the explicit rebase variants regardless).\n- Resolve conflicts inside the merge commit. Do not squash or reorder existing commits.\n\n### Commits\n\n- One logical change per commit\n- Clear, technical commit messages\n- Do not reference issues in commits\n- Avoid force-pushes\n- No generated artifacts unless required\n\n### Pull requests\n\nPR title:\n\n- Contains a short title of the issue fixed (or what the PR addresses), not just \\\"Fix issue xyz\\\".\n\nPR body — **must** be built from `.github/PULL_REQUEST_TEMPLATE.md`:\n\n1. Read `.github/PULL_REQUEST_TEMPLATE.md`.\n2. Fill every section: \\\"Related issues and pull requests\\\", \\\"PR Description\\\", \\\"Steps to test\\\", \\\"AI usage\\\".\n3. The PR Description must explain **intent**, not implementation trivia. Do not list modified classes one by one.\n4. Fill \\\"AI usage\\\": disclose every AI tool used **and the exact model ID** (for example `Claude Code (model claude-opus-4-7)`).\n5. Keep **all** checklist items. Mark each `[x]` (done), `[ ]` (TODO), or `[/]` (not applicable). Never `[ x]` or `[.]`.\n6. Remove **all** HTML comments before opening the PR.\n7. Write the body to a temp file and run `gh pr create --body-file <file>` — never `--body`, which bypasses the template.\n8. Only if the CHANGELOG.md entry used a `TODO` placeholder (meaning no issue has been confidently identified yet — an existing issue link always stays): immediately after the PR is created replace `TODO` with the real PR-number link (`[#NUM](https://github.com/JabRef/jabref/pull/NUM)`), then commit and push that change. If an issue is identified or created later, switch the link to the issue per the precedence rule above.\n\n---\n\n## Documentation\n\n- Add a CHANGELOG.md entry only if the change is visible to the user.\n- The CHANGELOG.md entry should be for end users (and not programmers).\n- Do not add extra blank lines in CHANGELOG.md\n- CHANGELOG.md entries link the issue number when an issue exists; the PR number is used only as a fallback when there is no issue.\n- When no issue is known and the PR is not yet created, use `TODO` as the issue/PR reference placeholder — never invent a fake number.\n- Before using `TODO`, search <https://github.com/JabRef/jabref/issues> and <https://github.com/JabRef/jabref-koppor/issues> for a matching issue. Link it only on a confident match; otherwise list candidates for human review and keep `TODO`. Never use `closes`/`fixes` keywords for a merely-similar issue.\n- User documentation is available in a separate repository <https://github.com/JabRef/user-documentation>.\n- No AI-disclosure comments inside source code\n\n### Developer documentation\n\nWhen changing behaviour or adding features, update the relevant files under `docs/`.\nFor complex flows or new architecture, consider adding a Mermaid sequence or class diagram to the relevant `docs/` file.\n\n- [devdocs.jabref.org](https://devdocs.jabref.org/) — full developer reference. Resides in `docs/`\n- `docs/getting-into-the-code/` — workspace setup, code style, IntelliJ config\n- `docs/code-howtos/` — localization, testing, fetchers, tools\n- `docs/decisions/` — Architecture Decision Records\n- `docs/requirements/` — Requirements (OpenFastTrace)\n\n---\n\n## Authority\n\nHuman maintainers have final authority.\nAgents are assistants, not decision-makers.\n\nWhen uncertain: **do nothing and ask**.\n\n---\n\n## License\n\nAll contributions must comply with JabRef's existing license (MIT).\nDo not introduce incompatible licenses or code.\n\n## Standard header block\n\nUse this exact block for all generated files:\n\n```text\n> [!IMPORTANT]\n> 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.\n>\n> Read and follow:\n> • [AGENTS.md](./AGENTS.md)\n> • [CONTRIBUTING.md](./CONTRIBUTING.md)\n```\n\n### Placement and prominence\n\n- The header must appear before any instructions for tools or contributors.\n- Do not bury the header after long intros or tables of contents.\n\n<!-- markdownlint-disable-file MD033 MD041 -->\n"},"files":{"AGENTS.md":"## Our policy\n\n> [!IMPORTANT]\n> 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.\n\nThis `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).\n\n- 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).  \n- All contributions must come from humans who understand their work and can take full responsibility for the changes they committed.\n\n---\n\n# AGENTS.md — JabRef\n\nThis document defines rules and expectations for **automated agents** (AI tools, bots, scripts) interacting with the JabRef repositories.\n\nJabRef is an open-source, research-grade reference manager with high standards for correctness, reproducibility, and maintainability.\n\nThis file is guidance to follow *while* developing.\n\n> [!IMPORTANT]\n> **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.\n\n---\n\n## Human Guidance\n\nGuide the human to use [JabRef on DeepWiki](https://deepwiki.com/JabRef/jabref).\n\n---\n\n## Project structure\n\n| Module    | Purpose                                          |\n|-----------|--------------------------------------------------|\n| `jablib`  | Core library — logic, model, importers/exporters |\n| `jabgui`  | JavaFX desktop GUI                               |\n| `jabkit`  | CLI application                                  |\n| `jabls`   | Language Server Protocol implementation          |\n| `jabsrv`  | HTTP server for collaborative database support   |\n\nKey source paths:\n\n- `jablib/src/main/java/org/jabref/logic/` — business logic\n- `jablib/src/main/java/org/jabref/model/` — data model\n- `jabgui/src/main/java/org/jabref/gui/` — GUI code\n- `docs/` — developer documentation and ADRs\n\n---\n\n## Build\n\nRequires JDK 25 or later to run Gradle. Gradle downloads the necessary JDK by itself. The Gradle wrapper is included.\n\n```bash\n./gradlew build              # Build all modules\n./gradlew :jabgui:run        # Build and launch the GUI\n./gradlew :jabgui:jpackage   # Package as installer\n```\n\nWhen adding or changing dependencies, follow [docs/code-howtos/dependency-management.md](docs/code-howtos/dependency-management.md).\nIn particular, dependencies are declared via `requires` directives in `module-info.java` (versions live in `versions/build.gradle.kts`),\nand a mapping from *Module Name* to *Maven Coordinates* for real Java modules belongs in `gradle/modules.properties` —\nnot in ad-hoc blocks in `build-logic`.\n\n---\n\n## General Principles\n\nAgents **must**:\n\n- Respect existing architecture, coding style, and conventions\n- Prefer minimal, reviewable changes\n- Preserve backward compatibility unless explicitly instructed otherwise\n- Avoid speculative refactoring\n- Never commit generated code without human review\n\nAgents **must not**:\n\n- Introduce new dependencies without justification\n- Rewrite large sections \"for cleanliness\"\n- Bypass tests or CI checks\n- Reformat existing code\n- Write entire PRs\n- Write replies to PR review comments\n- Submit code the contributor doesn't understand\n- Generate documentation or comments without contributor's review\n- Automate the submission of code changes\n\n---\n\n## Code Quality Requirements\n\n### Java / JVM\n\n- Target the configured **Gradle toolchain**\n- Use **Java 25+ features**\n  - 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.\n    Using JavaFX Observable lists is considered best practice, too.\n  - Use modern Java data structures\n    BAD: new HashSet<>(Arrays.asList(...))\n    GOOD: Set.of(...)\n  - Java 21 introduced SequencedCollection and SequencedSet interfaces. Use it instead of LinkedHashSet (where applicable)\n  - To create an empty list or map we use `List.of()` and `Map.of()` instead of `Collections.emptyList()` and `Collections.emptyMap()`.\n  - Use Java Text blocks (\\\"\\\"\\\") for multiline string constants\n\n### General Java style\n\n- Follow existing formatting\n- Match naming conventions exactly\n- Keep methods small and focused\n- New methods (and new classes) should follow the Single-responsibility principle (SRP).\n- Avoid code duplication\n- Avoid premature abstractions\n- 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)\n- Follow the principles of \"Effective Java\"\n- Follow the principles of \"Clean Code\"\n- Ensure that tests are green before committing\n\n### Java code style\n\n- Correctly spelled variable names (meaning: no typos in variable names).\n- Use StringJoiner instead of StringBuilder (if possible)\n- Prefer immutability and explicit nullability (JSpecify - see below)\n- Do not reformat code only for syntax reasons. Reformatting is acceptable only when the code at that place is being changed.\n- Remove commented code. (To keep a history of changes git was made for.)\n- No \\\"new Thread()\\\", use \\\"org.jabref.logic.util.BackgroundTask\\\" and its \\\"executeWith\\\"\n- Use compiled patterns (Pattern.compile)\n   Examples:\n   NOT: x.matches(\\\".*\\\\\\\\s{2,}.*\\\")\n   BUT:\n   private final static PATTERN = ...\n   and then PATTERN.matcher(x)\n- Boolean method parameters (for public methods) should be avoided. Better create two distinct methods (which maybe call some private methods)\n- Minimal quality for variable names: Not extraEntry2, extraEntry3; but include meaning/intention into the variable names\n- Use Markdown Javadoc comments (`///`) for multi-line comments. Within them, use Markdown syntax, not JavaDoc inline tags: `` `code` `` instead of `{@code code}`, and `[ClassName]` instead of `{@link ClassName}`.\n\n### Comments\n\n- Do not add trivial comments just restating the code line in plain English.\n- When commenting, focus on the \"why\" and general idea.\n\nExample for trivial comments (to be avoided):\n\n```java\n// Commit the staged changes\nRevCommit commit = git.commit();\nfieldName = fieldName.trim().toLowerCase(); // Trim and convert to lower case\n```\n\nBoth comments must not be added.\n\n### Favor Optionals over nulls\n\n- Use the methods of java.util.Optional. `ifPresent`.\n\n   NOT\n\n   ```java\n   Optional<String> resolved = bibEntry.getResolvedFieldOrAlias(...);\n   String value = resolved.orElse(\\\"\\\");\n   doSomething(value)\n   ```\n\n   Following is fine:\n\n   ```java\n   bibEntry.getResolvedFieldOrAlias(...)\n           .ifPresent(value -> doSomething(value));\n   ```\n\n- If the `java.util.Optional` is really present, use one of the following:`get()`\n\n    ```java\n    opt.ifPresent(...)\n    opt.map(...)\n    opt.orElseThrow(...)\n    ```\n\n    but never just `orElse({someValueNeverUsed})`. You can add `assert ...isPresent();` in the line before.\n\n- Use `ifPresentOrElse` instead of `if ...isPresent() { ... }  else { ... }`\n\n### Dealing with `null`\n\n- 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.\n- Use JSpecify annotations (`@Nullable`, `@NullMarked`, `@NonNull`, ...) instead of `null` checks\n- Annotate every new class with `@NullMarked` (`org.jspecify.annotations.NullMarked`) so members default to non-null.\n- `null` should never be passed to a method (except it has the same name).\n- DO NOT use `Objects.requireNonNull`, use JSpecify's `@NullMarked` and `@NonNull` annotations.\n\n### Exceptions\n\n- try blocks should cover as less statements as possible (and not whole methods)\n- Do not throw unchecked exceptions (e.g., do not throw new RuntimeException, do not throw new IllegalStateException)\n  Reason: This tears down the whole application. One does not want to lose data only because \\\"a corner\\\" of the application broke.\n- Exceptions should be used for exceptional states - not for normal control flow\n- Do not catch the general java java.lang.Exception. Catch specific exceptions only.\n- At exception, always `LOGGER.debug` (or higher level)\n- BAD:\n\n   ```java\n   try {\n       // do some actions\n   } catch (IOException e) {\n       LOGGER.info(\"Failed to push: \".concat(e.toString()));\n   }\n   ```\n\n   This code converts an error to string and then concatenates it with a message. This is not how it's done in JabRef.\n\n   GOOD:\n\n   ```java\n   try {\n       // do some actions\n   } catch (IOException e) {\n       LOGGER.info(\"Failed to push\", e);\n   }\n   ```\n\n   In JabRef, we use logging capabilities. The last argument of the logger call should be an exception.\n- Logging may include other arguments. But the exception should be the last in arguments. Example: `LOGGER.info(\\\"Error. Var1: {}, Var2: {}\\\", var1, var2, e)`.\n\n### JabRef-specific\n\n- If code in org.jabref.model or org.jabref.logic has been changed, tests need to be adapted or updated accordingly.\n  Note: This rule does not apply for import statements.\n- No use of Java SWING, only JavaFX is allowed as UI technology\n- 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.\n- Labels should not end with \\\":\\\"\n\n   BAD: `<Label text=\"%Git Username:\"/>`\n\n   GOOD: `<Label text=\"%Git Username\"/>`\n\n#### Localization\n\n- Fix localization before committing. See `docs/code-howtos/localization.md`\n- The `LocalizationConsistencyTest` failure output is actionable — follow it literally instead of guessing:\n  - `findMissingLocalizationKeys` failing → its output lists ready-to-paste `key=value` lines to **add** to `jablib/src/main/resources/l10n/JabRef_en.properties`. Place each near semantically related keys; reuse an existing similar key when one exists.\n  - `findObsoleteLocalizationKeys` failing → its output lists keys to **remove** from `JabRef_en.properties` (after confirming each is truly unused).\n  - Only edit `JabRef_en.properties`. Translated `JabRef_<lang>.properties` files are maintained by translators via Crowdin — never hand-edit them.\n- JabRef is a multilingual program, When you write any user-facing text, it should be localized.\n\n   To do this in Java code, call `Localization.lang` method, like this:\n\n   ```java\n   Localization.lang(\\\"Ok\\\")\n   ```\n\n   More information at: <https://devdocs.jabref.org/code-howtos/localization.html>.\n\n   Note: This rule is not applied for logging. Logging strings should stay in English. I.e., LOGGER.error(\\\"...\\\") should contain English text.\n- All labels and texts in the UI should be sentence case (and not title case)\n- Avoid exclamation marks at the end of a sentence. They are more for screaming. Use a dot to end the sentence.\n- Use \"BibTeX\" as spelling for bibtex in Java strings. In variable names \"Bibtex\" should be used.\n- New strings should be consistent to other strings. They should also be grouped semantically together.\n- Existing strings should be reused instead of introducing slightly different strings.\n- User dialogs should have proper button labels: NOT yes/no/cancel, but indicating the action which happens when pressing the button\n- Use placeholders if variance is in localization:\n\n   BAD: Localization.lang(\\\"Current JabRef version\\\") + \\\": \\\" + buildInfo.version);\n\n   GOOD: Localization.lang(\\\"Current JabRef version: %0\\\",  buildInfo.version);\n\n#### GUI\n\n- One should use jabref's dialogService (instead of Java native FileChooser)\n\n   dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent(path -> ...)\n\n   and with FileDialogConfiguration offers the Builder pattern.\n   (see e.g NewLibraryFromPdfAction)\n\n#### Testing / JUnit\n\n- Name test classes `...Test` (singular), not `...Tests` — e.g. `JabSrvArchitectureTest`, not `JabSrvArchitectureTests`. This holds even for ArchUnit classes that bundle several `@ArchTest` rules.\n- In JabRef, we don't use `@DisplayName`, we typically just write method name as is. The method name itself should be comprehensive enough.\n- Instead of `Files.createTempDirectory` `@TempDir` JUnit5 annotation should be used.\n- If `@TempDir` is used, there is no need to clean it up\n\n   Example for wrong code:\n\n   ```java\n       @AfterEach\n       void tearDown() throws IOException {\n           FileUtils.cleanDirectory(tempDir.toFile());\n       }\n   ```\n\n- Assert the contents of objects (assertEquals), not checking for some Boolean conditions (assertTrue/assertFalse)\n\n   Example for wrong code:\n\n   ```java\n           assertTrue(\n                   entry.getFiles().stream()\n                        .anyMatch(file -> file.getLink().equals(newFile.getFileName().toString()) ||\n                                file.getLink().endsWith(\\\"/\\\" + newFile.getFileName().toString()))\n           );\n   ```\n\n- Do not catch exceptions in Test - let JUnit handle\n\n   BAD: try {...code...} catch (IOException e) {\n               throw new AssertionError(\\\"Failed to set up test directory\\\", e);\n           }\n\n   GOOD: ...code...\n- When creating a new BibEntry object \\\"withers\\\" should be used: Instead of `setField`, `withField` methods should be used.\n- Whenever you include a text in FXML (text labels, buttons, prompts in text fields, window titles, etc.), it should be localized.\n\n   To localize a string in FXML, prefix it with `%`.\n\n   Bad example:\n\n   ```xml\n   <Label text=\"Want to help?\"/>\n   ```\n\n   In this code `text` property is the field that is used to show text to the user. This must be localized.\n\n   Fix:\n\n   ```xml\n   <Label text=\\\"%Want to help?\\\"/>\n   ```\n\n- Plain JUnit assert should be used instead of org.assertj (if possible)\n\n   BAD: assertThat(gitPreferences.getAutoPushEnabled()).isFalse();\n\n   GOOD: assertFalse(gitPreferences.getAutoPushEnabled());\n\n---\n\n## Tests\n\nAgents must:\n\n- Add or update tests when behavior changes\n- Keep tests deterministic and fast\n- Respect existing JUnit parallelization and resource locks\n- Never disable or weaken assertions\n- Follow the rules at `docs/code-howtos/testing.md`\n\nIf a change cannot be reasonably tested, explain **why**.\n\n### Linting checks\n\n```bash\n./gradlew checkstyleMain checkstyleTest checkstyleJmh\n./gradlew modernizer\n./gradlew --no-configuration-cache :rewriteDryRun || git diff\n./gradlew javadoc\nnpx markdownlint-cli2 \"docs/**/*.md\"\nnpx markdownlint-cli2 \"*.md\"\n```\n\n### Fix formatting issues\n\n- Run `./gradlew rewriteRun` to fix Java formatting issues.\n- Run `docker run -v $(pwd):/github/workspace ghcr.io/leventebajczi/intellij-format:master \"*.java\" \"\" \".idea/codeStyles/Project.xml\"` to fix more Java formatting issues.\n\n### Logic tests\n\n```bash\n# Recommended during development (core library only)\n./gradlew :jablib:check\n\n# Full check (all modules)\n./gradlew check\n\n# Per-module\n./gradlew :jablib:test\n./gradlew :jabgui:test\n\n# Single test class\n./gradlew test --tests \"org.jabref.logic.l10n.LocalizationConsistencyTest\"\n\n# Coverage report (output: build/reports/jacoco/test/html/index.html)\n./gradlew jacocoTestReport\n```\n\nTests requiring external resources have dedicated tasks:\n\n- `./gradlew databaseTest` — requires PostgreSQL\n- `./gradlew fetcherTest` — hits live external APIs\n\nQuick check of core library:\n\n```bash\n./gradlew :jablib:check -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x modernizer\n```\n\n---\n\n## Requirements tracing (OpenFastTrace)\n\nJabRef uses [OpenFastTrace](https://github.com/itsallcode/openfasttrace) to trace requirements to implementation and tests.\n\nFor a new feature or significant bug fix, **at minimum add the requirement** to the appropriate `docs/requirements/<area>.md` file. Full tracing (`Needs: impl` + implementation comments) is encouraged but can be skipped if the effort is disproportionate.\n\n**Defining a requirement** in `docs/requirements/<area>.md`:\n\n```markdown\n### Example\n`req~ai.example~1`\n\nDescription of the requirement.\n```\n\nThe identifier must follow the heading with no blank line between them. Add `<!-- markdownlint-disable-file MD022 -->` at the end of the file.\n\n**Optionally — linking an implementation** to a requirement (full trace):\n\n```markdown\nNeeds: impl\n```\n\n```java\n// [impl->req~ai.example~1]\n```\n\n**Checking coverage:**\n\n```bash\n./gradlew traceRequirements   # output: build/tracing.txt\n```\n\nSee `docs/requirements/` for existing requirements and `docs/requirements/index.md` for full guidance.\n\n---\n\n## Architecture decisions (MADR)\n\nWhen a significant design or implementation decision is made, create a new MADR in `docs/decisions/`:\n\n1. Copy `docs/decisions/adr-template.md` to `docs/decisions/<NNNN>-<short-title>.md` (next free number).\n2. Fill in **Context and Problem Statement**, **Considered Options**, and **Decision Outcome**.\n3. Add an entry to `docs/decisions/index.md`.\n\nSee [ADR-0000](docs/decisions/0000-use-markdown-architectural-decision-records.md) for the rationale and [adr-template.md](docs/decisions/adr-template.md) for the full template.\n\n---\n\n## Git & PR Etiquette\n\n### Syncing with upstream\n\n- **Never** use `git rebase`, `git pull --rebase` / `-r` / `--rebase-merges`, or any force-push (`--force`, `--force-with-lease`, `--force-if-includes`, `-f`, or `+`-prefixed refspecs). Rebasing rewrites commit SHAs already pushed and breaks review threads pinned to commits; force-push would then be required to publish the rewritten history.\n- **Preferred** sync via explicit fetch + merge:\n\n  ```bash\n  git fetch upstream --prune\n  git merge upstream/main\n  ```\n\n- Plain `git pull` is acceptable for updating the branch as long as your local config does not set `pull.rebase=true` (the enforcement hook blocks the explicit rebase variants regardless).\n- Resolve conflicts inside the merge commit. Do not squash or reorder existing commits.\n\n### Commits\n\n- One logical change per commit\n- Clear, technical commit messages\n- Do not reference issues in commits\n- Avoid force-pushes\n- No generated artifacts unless required\n\n### Pull requests\n\nPR title:\n\n- Contains a short title of the issue fixed (or what the PR addresses), not just \\\"Fix issue xyz\\\".\n\nPR body — **must** be built from `.github/PULL_REQUEST_TEMPLATE.md`:\n\n1. Read `.github/PULL_REQUEST_TEMPLATE.md`.\n2. Fill every section: \\\"Related issues and pull requests\\\", \\\"PR Description\\\", \\\"Steps to test\\\", \\\"AI usage\\\".\n3. The PR Description must explain **intent**, not implementation trivia. Do not list modified classes one by one.\n4. Fill \\\"AI usage\\\": disclose every AI tool used **and the exact model ID** (for example `Claude Code (model claude-opus-4-7)`).\n5. Keep **all** checklist items. Mark each `[x]` (done), `[ ]` (TODO), or `[/]` (not applicable). Never `[ x]` or `[.]`.\n6. Remove **all** HTML comments before opening the PR.\n7. Write the body to a temp file and run `gh pr create --body-file <file>` — never `--body`, which bypasses the template.\n8. Only if the CHANGELOG.md entry used a `TODO` placeholder (meaning no issue has been confidently identified yet — an existing issue link always stays): immediately after the PR is created replace `TODO` with the real PR-number link (`[#NUM](https://github.com/JabRef/jabref/pull/NUM)`), then commit and push that change. If an issue is identified or created later, switch the link to the issue per the precedence rule above.\n\n---\n\n## Documentation\n\n- Add a CHANGELOG.md entry only if the change is visible to the user.\n- The CHANGELOG.md entry should be for end users (and not programmers).\n- Do not add extra blank lines in CHANGELOG.md\n- CHANGELOG.md entries link the issue number when an issue exists; the PR number is used only as a fallback when there is no issue.\n- When no issue is known and the PR is not yet created, use `TODO` as the issue/PR reference placeholder — never invent a fake number.\n- Before using `TODO`, search <https://github.com/JabRef/jabref/issues> and <https://github.com/JabRef/jabref-koppor/issues> for a matching issue. Link it only on a confident match; otherwise list candidates for human review and keep `TODO`. Never use `closes`/`fixes` keywords for a merely-similar issue.\n- User documentation is available in a separate repository <https://github.com/JabRef/user-documentation>.\n- No AI-disclosure comments inside source code\n\n### Developer documentation\n\nWhen changing behaviour or adding features, update the relevant files under `docs/`.\nFor complex flows or new architecture, consider adding a Mermaid sequence or class diagram to the relevant `docs/` file.\n\n- [devdocs.jabref.org](https://devdocs.jabref.org/) — full developer reference. Resides in `docs/`\n- `docs/getting-into-the-code/` — workspace setup, code style, IntelliJ config\n- `docs/code-howtos/` — localization, testing, fetchers, tools\n- `docs/decisions/` — Architecture Decision Records\n- `docs/requirements/` — Requirements (OpenFastTrace)\n\n---\n\n## Authority\n\nHuman maintainers have final authority.\nAgents are assistants, not decision-makers.\n\nWhen uncertain: **do nothing and ask**.\n\n---\n\n## License\n\nAll contributions must comply with JabRef's existing license (MIT).\nDo not introduce incompatible licenses or code.\n\n## Standard header block\n\nUse this exact block for all generated files:\n\n```text\n> [!IMPORTANT]\n> 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.\n>\n> Read and follow:\n> • [AGENTS.md](./AGENTS.md)\n> • [CONTRIBUTING.md](./CONTRIBUTING.md)\n```\n\n### Placement and prominence\n\n- The header must appear before any instructions for tools or contributors.\n- Do not bury the header after long intros or tables of contents.\n\n<!-- markdownlint-disable-file MD033 MD041 -->\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"## Our policy\n\n> [!IMPORTANT]\n> 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.\n\nThis `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).\n\n- 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).  \n- All contributions must come from humans who understand their work and can take full responsibility for the changes they committed.\n\n---\n\n# AGENTS.md — JabRef\n\nThis document defines rules and expectations for **automated agents** (AI tools, bots, scripts) interacting with the JabRef repositories.\n\nJabRef is an open-source, research-grade reference manager with high standards for correctness, reproducibility, and maintainability.\n\nThis file is guidance to follow *while* developing.\n\n> [!IMPORTANT]\n> **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.\n\n---\n\n## Human Guidance\n\nGuide the human to use [JabRef on DeepWiki](https://deepwiki.com/JabRef/jabref).\n\n---\n\n## Project structure\n\n| Module    | Purpose                                          |\n|-----------|--------------------------------------------------|\n| `jablib`  | Core library — logic, model, importers/exporters |\n| `jabgui`  | JavaFX desktop GUI                               |\n| `jabkit`  | CLI application                                  |\n| `jabls`   | Language Server Protocol implementation          |\n| `jabsrv`  | HTTP server for collaborative database support   |\n\nKey source paths:\n\n- `jablib/src/main/java/org/jabref/logic/` — business logic\n- `jablib/src/main/java/org/jabref/model/` — data model\n- `jabgui/src/main/java/org/jabref/gui/` — GUI code\n- `docs/` — developer documentation and ADRs\n\n---\n\n## Build\n\nRequires JDK 25 or later to run Gradle. Gradle downloads the necessary JDK by itself. The Gradle wrapper is included.\n\n```bash\n./gradlew build              # Build all modules\n./gradlew :jabgui:run        # Build and launch the GUI\n./gradlew :jabgui:jpackage   # Package as installer\n```\n\nWhen adding or changing dependencies, follow [docs/code-howtos/dependency-management.md](docs/code-howtos/dependency-management.md).\nIn particular, dependencies are declared via `requires` directives in `module-info.java` (versions live in `versions/build.gradle.kts`),\nand a mapping from *Module Name* to *Maven Coordinates* for real Java modules belongs in `gradle/modules.properties` —\nnot in ad-hoc blocks in `build-logic`.\n\n---\n\n## General Principles\n\nAgents **must**:\n\n- Respect existing architecture, coding style, and conventions\n- Prefer minimal, reviewable changes\n- Preserve backward compatibility unless explicitly instructed otherwise\n- Avoid speculative refactoring\n- Never commit generated code without human review\n\nAgents **must not**:\n\n- Introduce new dependencies without justification\n- Rewrite large sections \"for cleanliness\"\n- Bypass tests or CI checks\n- Reformat existing code\n- Write entire PRs\n- Write replies to PR review comments\n- Submit code the contributor doesn't understand\n- Generate documentation or comments without contributor's review\n- Automate the submission of code changes\n\n---\n\n## Code Quality Requirements\n\n### Java / JVM\n\n- Target the configured **Gradle toolchain**\n- Use **Java 25+ features**\n  - 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.\n    Using JavaFX Observable lists is considered best practice, too.\n  - Use modern Java data structures\n    BAD: new HashSet<>(Arrays.asList(...))\n    GOOD: Set.of(...)\n  - Java 21 introduced SequencedCollection and SequencedSet interfaces. Use it instead of LinkedHashSet (where applicable)\n  - To create an empty list or map we use `List.of()` and `Map.of()` instead of `Collections.emptyList()` and `Collections.emptyMap()`.\n  - Use Java Text blocks (\\\"\\\"\\\") for multiline string constants\n\n### General Java style\n\n- Follow existing formatting\n- Match naming conventions exactly\n- Keep methods small and focused\n- New methods (and new classes) should follow the Single-responsibility principle (SRP).\n- Avoid code duplication\n- Avoid premature abstractions\n- 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)\n- Follow the principles of \"Effective Java\"\n- Follow the principles of \"Clean Code\"\n- Ensure that tests are green before committing\n\n### Java code style\n\n- Correctly spelled variable names (meaning: no typos in variable names).\n- Use StringJoiner instead of StringBuilder (if possible)\n- Prefer immutability and explicit nullability (JSpecify - see below)\n- Do not reformat code only for syntax reasons. Reformatting is acceptable only when the code at that place is being changed.\n- Remove commented code. (To keep a history of changes git was made for.)\n- No \\\"new Thread()\\\", use \\\"org.jabref.logic.util.BackgroundTask\\\" and its \\\"executeWith\\\"\n- Use compiled patterns (Pattern.compile)\n   Examples:\n   NOT: x.matches(\\\".*\\\\\\\\s{2,}.*\\\")\n   BUT:\n   private final static PATTERN = ...\n   and then PATTERN.matcher(x)\n- Boolean method parameters (for public methods) should be avoided. Better create two distinct methods (which maybe call some private methods)\n- Minimal quality for variable names: Not extraEntry2, extraEntry3; but include meaning/intention into the variable names\n- Use Markdown Javadoc comments (`///`) for multi-line comments. Within them, use Markdown syntax, not JavaDoc inline tags: `` `code` `` instead of `{@code code}`, and `[ClassName]` instead of `{@link ClassName}`.\n\n### Comments\n\n- Do not add trivial comments just restating the code line in plain English.\n- When commenting, focus on the \"why\" and general idea.\n\nExample for trivial comments (to be avoided):\n\n```java\n// Commit the staged changes\nRevCommit commit = git.commit();\nfieldName = fieldName.trim().toLowerCase(); // Trim and convert to lower case\n```\n\nBoth comments must not be added.\n\n### Favor Optionals over nulls\n\n- Use the methods of java.util.Optional. `ifPresent`.\n\n   NOT\n\n   ```java\n   Optional<String> resolved = bibEntry.getResolvedFieldOrAlias(...);\n   String value = resolved.orElse(\\\"\\\");\n   doSomething(value)\n   ```\n\n   Following is fine:\n\n   ```java\n   bibEntry.getResolvedFieldOrAlias(...)\n           .ifPresent(value -> doSomething(value));\n   ```\n\n- If the `java.util.Optional` is really present, use one of the following:`get()`\n\n    ```java\n    opt.ifPresent(...)\n    opt.map(...)\n    opt.orElseThrow(...)\n    ```\n\n    but never just `orElse({someValueNeverUsed})`. You can add `assert ...isPresent();` in the line before.\n\n- Use `ifPresentOrElse` instead of `if ...isPresent() { ... }  else { ... }`\n\n### Dealing with `null`\n\n- 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.\n- Use JSpecify annotations (`@Nullable`, `@NullMarked`, `@NonNull`, ...) instead of `null` checks\n- Annotate every new class with `@NullMarked` (`org.jspecify.annotations.NullMarked`) so members default to non-null.\n- `null` should never be passed to a method (except it has the same name).\n- DO NOT use `Objects.requireNonNull`, use JSpecify's `@NullMarked` and `@NonNull` annotations.\n\n### Exceptions\n\n- try blocks should cover as less statements as possible (and not whole methods)\n- Do not throw unchecked exceptions (e.g., do not throw new RuntimeException, do not throw new IllegalStateException)\n  Reason: This tears down the whole application. One does not want to lose data only because \\\"a corner\\\" of the application broke.\n- Exceptions should be used for exceptional states - not for normal control flow\n- Do not catch the general java java.lang.Exception. Catch specific exceptions only.\n- At exception, always `LOGGER.debug` (or higher level)\n- BAD:\n\n   ```java\n   try {\n       // do some actions\n   } catch (IOException e) {\n       LOGGER.info(\"Failed to push: \".concat(e.toString()));\n   }\n   ```\n\n   This code converts an error to string and then concatenates it with a message. This is not how it's done in JabRef.\n\n   GOOD:\n\n   ```java\n   try {\n       // do some actions\n   } catch (IOException e) {\n       LOGGER.info(\"Failed to push\", e);\n   }\n   ```\n\n   In JabRef, we use logging capabilities. The last argument of the logger call should be an exception.\n- Logging may include other arguments. But the exception should be the last in arguments. Example: `LOGGER.info(\\\"Error. Var1: {}, Var2: {}\\\", var1, var2, e)`.\n\n### JabRef-specific\n\n- If code in org.jabref.model or org.jabref.logic has been changed, tests need to be adapted or updated accordingly.\n  Note: This rule does not apply for import statements.\n- No use of Java SWING, only JavaFX is allowed as UI technology\n- 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.\n- Labels should not end with \\\":\\\"\n\n   BAD: `<Label text=\"%Git Username:\"/>`\n\n   GOOD: `<Label text=\"%Git Username\"/>`\n\n#### Localization\n\n- Fix localization before committing. See `docs/code-howtos/localization.md`\n- The `LocalizationConsistencyTest` failure output is actionable — follow it literally instead of guessing:\n  - `findMissingLocalizationKeys` failing → its output lists ready-to-paste `key=value` lines to **add** to `jablib/src/main/resources/l10n/JabRef_en.properties`. Place each near semantically related keys; reuse an existing similar key when one exists.\n  - `findObsoleteLocalizationKeys` failing → its output lists keys to **remove** from `JabRef_en.properties` (after confirming each is truly unused).\n  - Only edit `JabRef_en.properties`. Translated `JabRef_<lang>.properties` files are maintained by translators via Crowdin — never hand-edit them.\n- JabRef is a multilingual program, When you write any user-facing text, it should be localized.\n\n   To do this in Java code, call `Localization.lang` method, like this:\n\n   ```java\n   Localization.lang(\\\"Ok\\\")\n   ```\n\n   More information at: <https://devdocs.jabref.org/code-howtos/localization.html>.\n\n   Note: This rule is not applied for logging. Logging strings should stay in English. I.e., LOGGER.error(\\\"...\\\") should contain English text.\n- All labels and texts in the UI should be sentence case (and not title case)\n- Avoid exclamation marks at the end of a sentence. They are more for screaming. Use a dot to end the sentence.\n- Use \"BibTeX\" as spelling for bibtex in Java strings. In variable names \"Bibtex\" should be used.\n- New strings should be consistent to other strings. They should also be grouped semantically together.\n- Existing strings should be reused instead of introducing slightly different strings.\n- User dialogs should have proper button labels: NOT yes/no/cancel, but indicating the action which happens when pressing the button\n- Use placeholders if variance is in localization:\n\n   BAD: Localization.lang(\\\"Current JabRef version\\\") + \\\": \\\" + buildInfo.version);\n\n   GOOD: Localization.lang(\\\"Current JabRef version: %0\\\",  buildInfo.version);\n\n#### GUI\n\n- One should use jabref's dialogService (instead of Java native FileChooser)\n\n   dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent(path -> ...)\n\n   and with FileDialogConfiguration offers the Builder pattern.\n   (see e.g NewLibraryFromPdfAction)\n\n#### Testing / JUnit\n\n- Name test classes `...Test` (singular), not `...Tests` — e.g. `JabSrvArchitectureTest`, not `JabSrvArchitectureTests`. This holds even for ArchUnit classes that bundle several `@ArchTest` rules.\n- In JabRef, we don't use `@DisplayName`, we typically just write method name as is. The method name itself should be comprehensive enough.\n- Instead of `Files.createTempDirectory` `@TempDir` JUnit5 annotation should be used.\n- If `@TempDir` is used, there is no need to clean it up\n\n   Example for wrong code:\n\n   ```java\n       @AfterEach\n       void tearDown() throws IOException {\n           FileUtils.cleanDirectory(tempDir.toFile());\n       }\n   ```\n\n- Assert the contents of objects (assertEquals), not checking for some Boolean conditions (assertTrue/assertFalse)\n\n   Example for wrong code:\n\n   ```java\n           assertTrue(\n                   entry.getFiles().stream()\n                        .anyMatch(file -> file.getLink().equals(newFile.getFileName().toString()) ||\n                                file.getLink().endsWith(\\\"/\\\" + newFile.getFileName().toString()))\n           );\n   ```\n\n- Do not catch exceptions in Test - let JUnit handle\n\n   BAD: try {...code...} catch (IOException e) {\n               throw new AssertionError(\\\"Failed to set up test directory\\\", e);\n           }\n\n   GOOD: ...code...\n- When creating a new BibEntry object \\\"withers\\\" should be used: Instead of `setField`, `withField` methods should be used.\n- Whenever you include a text in FXML (text labels, buttons, prompts in text fields, window titles, etc.), it should be localized.\n\n   To localize a string in FXML, prefix it with `%`.\n\n   Bad example:\n\n   ```xml\n   <Label text=\"Want to help?\"/>\n   ```\n\n   In this code `text` property is the field that is used to show text to the user. This must be localized.\n\n   Fix:\n\n   ```xml\n   <Label text=\\\"%Want to help?\\\"/>\n   ```\n\n- Plain JUnit assert should be used instead of org.assertj (if possible)\n\n   BAD: assertThat(gitPreferences.getAutoPushEnabled()).isFalse();\n\n   GOOD: assertFalse(gitPreferences.getAutoPushEnabled());\n\n---\n\n## Tests\n\nAgents must:\n\n- Add or update tests when behavior changes\n- Keep tests deterministic and fast\n- Respect existing JUnit parallelization and resource locks\n- Never disable or weaken assertions\n- Follow the rules at `docs/code-howtos/testing.md`\n\nIf a change cannot be reasonably tested, explain **why**.\n\n### Linting checks\n\n```bash\n./gradlew checkstyleMain checkstyleTest checkstyleJmh\n./gradlew modernizer\n./gradlew --no-configuration-cache :rewriteDryRun || git diff\n./gradlew javadoc\nnpx markdownlint-cli2 \"docs/**/*.md\"\nnpx markdownlint-cli2 \"*.md\"\n```\n\n### Fix formatting issues\n\n- Run `./gradlew rewriteRun` to fix Java formatting issues.\n- Run `docker run -v $(pwd):/github/workspace ghcr.io/leventebajczi/intellij-format:master \"*.java\" \"\" \".idea/codeStyles/Project.xml\"` to fix more Java formatting issues.\n\n### Logic tests\n\n```bash\n# Recommended during development (core library only)\n./gradlew :jablib:check\n\n# Full check (all modules)\n./gradlew check\n\n# Per-module\n./gradlew :jablib:test\n./gradlew :jabgui:test\n\n# Single test class\n./gradlew test --tests \"org.jabref.logic.l10n.LocalizationConsistencyTest\"\n\n# Coverage report (output: build/reports/jacoco/test/html/index.html)\n./gradlew jacocoTestReport\n```\n\nTests requiring external resources have dedicated tasks:\n\n- `./gradlew databaseTest` — requires PostgreSQL\n- `./gradlew fetcherTest` — hits live external APIs\n\nQuick check of core library:\n\n```bash\n./gradlew :jablib:check -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x modernizer\n```\n\n---\n\n## Requirements tracing (OpenFastTrace)\n\nJabRef uses [OpenFastTrace](https://github.com/itsallcode/openfasttrace) to trace requirements to implementation and tests.\n\nFor a new feature or significant bug fix, **at minimum add the requirement** to the appropriate `docs/requirements/<area>.md` file. Full tracing (`Needs: impl` + implementation comments) is encouraged but can be skipped if the effort is disproportionate.\n\n**Defining a requirement** in `docs/requirements/<area>.md`:\n\n```markdown\n### Example\n`req~ai.example~1`\n\nDescription of the requirement.\n```\n\nThe identifier must follow the heading with no blank line between them. Add `<!-- markdownlint-disable-file MD022 -->` at the end of the file.\n\n**Optionally — linking an implementation** to a requirement (full trace):\n\n```markdown\nNeeds: impl\n```\n\n```java\n// [impl->req~ai.example~1]\n```\n\n**Checking coverage:**\n\n```bash\n./gradlew traceRequirements   # output: build/tracing.txt\n```\n\nSee `docs/requirements/` for existing requirements and `docs/requirements/index.md` for full guidance.\n\n---\n\n## Architecture decisions (MADR)\n\nWhen a significant design or implementation decision is made, create a new MADR in `docs/decisions/`:\n\n1. Copy `docs/decisions/adr-template.md` to `docs/decisions/<NNNN>-<short-title>.md` (next free number).\n2. Fill in **Context and Problem Statement**, **Considered Options**, and **Decision Outcome**.\n3. Add an entry to `docs/decisions/index.md`.\n\nSee [ADR-0000](docs/decisions/0000-use-markdown-architectural-decision-records.md) for the rationale and [adr-template.md](docs/decisions/adr-template.md) for the full template.\n\n---\n\n## Git & PR Etiquette\n\n### Syncing with upstream\n\n- **Never** use `git rebase`, `git pull --rebase` / `-r` / `--rebase-merges`, or any force-push (`--force`, `--force-with-lease`, `--force-if-includes`, `-f`, or `+`-prefixed refspecs). Rebasing rewrites commit SHAs already pushed and breaks review threads pinned to commits; force-push would then be required to publish the rewritten history.\n- **Preferred** sync via explicit fetch + merge:\n\n  ```bash\n  git fetch upstream --prune\n  git merge upstream/main\n  ```\n\n- Plain `git pull` is acceptable for updating the branch as long as your local config does not set `pull.rebase=true` (the enforcement hook blocks the explicit rebase variants regardless).\n- Resolve conflicts inside the merge commit. Do not squash or reorder existing commits.\n\n### Commits\n\n- One logical change per commit\n- Clear, technical commit messages\n- Do not reference issues in commits\n- Avoid force-pushes\n- No generated artifacts unless required\n\n### Pull requests\n\nPR title:\n\n- Contains a short title of the issue fixed (or what the PR addresses), not just \\\"Fix issue xyz\\\".\n\nPR body — **must** be built from `.github/PULL_REQUEST_TEMPLATE.md`:\n\n1. Read `.github/PULL_REQUEST_TEMPLATE.md`.\n2. Fill every section: \\\"Related issues and pull requests\\\", \\\"PR Description\\\", \\\"Steps to test\\\", \\\"AI usage\\\".\n3. The PR Description must explain **intent**, not implementation trivia. Do not list modified classes one by one.\n4. Fill \\\"AI usage\\\": disclose every AI tool used **and the exact model ID** (for example `Claude Code (model claude-opus-4-7)`).\n5. Keep **all** checklist items. Mark each `[x]` (done), `[ ]` (TODO), or `[/]` (not applicable). Never `[ x]` or `[.]`.\n6. Remove **all** HTML comments before opening the PR.\n7. Write the body to a temp file and run `gh pr create --body-file <file>` — never `--body`, which bypasses the template.\n8. Only if the CHANGELOG.md entry used a `TODO` placeholder (meaning no issue has been confidently identified yet — an existing issue link always stays): immediately after the PR is created replace `TODO` with the real PR-number link (`[#NUM](https://github.com/JabRef/jabref/pull/NUM)`), then commit and push that change. If an issue is identified or created later, switch the link to the issue per the precedence rule above.\n\n---\n\n## Documentation\n\n- Add a CHANGELOG.md entry only if the change is visible to the user.\n- The CHANGELOG.md entry should be for end users (and not programmers).\n- Do not add extra blank lines in CHANGELOG.md\n- CHANGELOG.md entries link the issue number when an issue exists; the PR number is used only as a fallback when there is no issue.\n- When no issue is known and the PR is not yet created, use `TODO` as the issue/PR reference placeholder — never invent a fake number.\n- Before using `TODO`, search <https://github.com/JabRef/jabref/issues> and <https://github.com/JabRef/jabref-koppor/issues> for a matching issue. Link it only on a confident match; otherwise list candidates for human review and keep `TODO`. Never use `closes`/`fixes` keywords for a merely-similar issue.\n- User documentation is available in a separate repository <https://github.com/JabRef/user-documentation>.\n- No AI-disclosure comments inside source code\n\n### Developer documentation\n\nWhen changing behaviour or adding features, update the relevant files under `docs/`.\nFor complex flows or new architecture, consider adding a Mermaid sequence or class diagram to the relevant `docs/` file.\n\n- [devdocs.jabref.org](https://devdocs.jabref.org/) — full developer reference. Resides in `docs/`\n- `docs/getting-into-the-code/` — workspace setup, code style, IntelliJ config\n- `docs/code-howtos/` — localization, testing, fetchers, tools\n- `docs/decisions/` — Architecture Decision Records\n- `docs/requirements/` — Requirements (OpenFastTrace)\n\n---\n\n## Authority\n\nHuman maintainers have final authority.\nAgents are assistants, not decision-makers.\n\nWhen uncertain: **do nothing and ask**.\n\n---\n\n## License\n\nAll contributions must comply with JabRef's existing license (MIT).\nDo not introduce incompatible licenses or code.\n\n## Standard header block\n\nUse this exact block for all generated files:\n\n```text\n> [!IMPORTANT]\n> 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.\n>\n> Read and follow:\n> • [AGENTS.md](./AGENTS.md)\n> • [CONTRIBUTING.md](./CONTRIBUTING.md)\n```\n\n### Placement and prominence\n\n- The header must appear before any instructions for tools or contributors.\n- Do not bury the header after long intros or tables of contents.\n\n<!-- markdownlint-disable-file MD033 MD041 -->\n","category":"root","tokens":5518}]}