{"owner":"JabRef","repo":"jabref","hasSkills":true,"totalSkillsCount":4,"totalTokensCount":7733,"categories":["root-instruction","mcp-config","marketplace","plugin-manifest"],"hasMcp":true,"mcpConfig":{"mcpServers":{"jabref":{"command":"npx","args":["-y","@modelcontextprotocol/server-jabref"]}}},"found":["AGENTS.md",".cursor/mcp.json",".claude-plugin/marketplace.json",".claude-plugin/plugin.json"],"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 instead of JavaDoc inline tags or HTML formatting tags: `` `code` `` instead of `{@code code}` or `<code>code</code>`, `[ClassName]` instead of `{@link ClassName}`, and fenced code blocks (```` ``` ````) instead of `<pre><code>`.\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- 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.\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- Deleting or renaming code orphans its keys, so run the test after such a change — and do not trust a green run you did not force. `LocalizationParser` walks `src/main/java` of every module (`jablib`, `jabkit`, `jabsrv`, `jabgui`, `jabls`) at test runtime, so those sources are not declared inputs of `:jablib:test`. The task is cacheable, and a `FROM-CACHE` or `UP-TO-DATE` result can hide a key that a deletion in another module just orphaned. Force it: `./gradlew :jablib:test --tests \"*LocalizationConsistencyTest*\" --rerun-tasks`\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 externalServicesTest` — hits live external APIs\n\nFetcher tests must always hit the live endpoints — do not mock or stub the remote API in fetcher tests.\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) (OFT) to trace requirements to implementation and tests.\nRequirements capture what JabRef should do as a structured representation of issues and features, enabling bidirectional traceability.\n\nFor a new feature or significant bug fix, add the requirement to the appropriate `docs/requirements/<area>.md` file.\n\nRead and use the [`openfasttrace`](https://github.com/itsallcode/openfasttrace-ai-skills/blob/main/skills/openfasttrace/SKILL.md) skill.\n\nIn JabRef we use OFT this way:\n\n- The requirements are put in `docs/requirements/<area>.md`.\n- The requirements are grouped by areas: `docs/requirements/ui.md`, `docs/requirements/git.md`, etc.\n- Title style:\n  - `req~` → **\"Subject must verb\"** (e.g., `## GitHub personal access token push access must be verifiable before sharing`).\n  - `feat~` → **\"User can verb\"** (e.g., `## User can share library via GitHub`).\n  - Avoid nominalizations: Write \"must be verified\" instead of \"verification\".\n  - One item, one requirement: If a title needs \"and\", split it into two separate requirements.\n  - The title carries the full normative statement: Anyone reading only the heading should understand the complete requirement constraint.\n- Use the description only for details that the title cannot carry:\n  - Triggering condition.\n  - Edge cases and boundary behavior.\n  - Brief rationale (if needed).\n  - Relevant GitHub issue link or context.\n\nArtifact types used:\n\n- `feat`: User-facing capability or broad feature (\"User can verb\").\n- `req`: Specific constraint, nuance, cross-cutting requirement, or bug fix the system must satisfy (\"Subject must verb\").\n- `impl`: Code implementation.\n- `utest`: Unit test.\n- `adr`: Architectural Decision Record.\n\n### Traceability chains\n\nIn JabRef, we use these traceability chains:\n\n- `feat` --> `impl`/`utest`\n- `req` --> `impl`/`utest`\n- `feat` --> `req` --> `impl`/`utest`\n- `adr` --> `impl`/`utest`\n\nAdditional guidelines:\n\n- Link the issue the requirement originates from (if there is).\n- Respect INVEST criteria. Prefer high-level requirements over overly detailed ones.\n- For ideas or planned requirements not yet implemented, mark them as draft so they are preserved without failing coverage checks: `Status: draft`.\n\nChecking coverage:\n\n```bash\n./gradlew traceRequirements   # output: build/reports/tracing.txt\n```\n\nSee `docs/requirements/` for existing requirements and [docs/code-howtos/requirements.md](docs/code-howtos/requirements.md) for full guidance. Also refer to the `openfasttrace` skill.\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\nTo link code to a decision, give the ADR an OpenFastTrace identifier directly below its title (no blank line in between)\nand declare what has to cover it:\n\n```markdown\n# Hardcode `StandardField` names\n`adr~hardcode-fieldnames~1`\n\nNeeds: impl\n```\n\n```java\n// [impl->adr~hardcode-fieldnames~1]\n```\n\nThe identifier's name part must not start with a digit, so drop the file's number prefix.\nAdd `<!-- markdownlint-disable-file MD022 -->` at the end of the ADR.\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- Before committing the merge, make sure no conflict marker is left: with `merge.conflictStyle=diff3` (the default here) a hunk has **four** markers — `<<<<<<<`, `|||||||` (the common-ancestor block), `=======`, `>>>>>>>` — and a resolution that only removes the outer ones leaves the ancestor block in the file. `git diff --cached --check` reports every leftover marker; run it after staging the resolved files.\n\n### Branches\n\n- `main` is the development branch; pull requests target it. `stable` is the last release plus ported fixes; CI labels a PR `dev: into-stable` when it links a bug issue (maintainers may add or remove the label by hand) and ports it after the merge. Never add that label to a port PR (`port-<number>-to-<branch>`). See [docs/contributing.md](docs/contributing.md#branching-strategy).\n\n### Commits\n\n- One logical change per commit\n- Clear, technical commit messages\n- Wrap annotations and other `@`-words in backticks in commit messages and PR texts (`` `@Nullable` ``); GitHub turns a plain `@Nullable` into a mention of that user\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. \\\"Steps to test\\\" is a numbered list of concrete steps ending in what the reviewer should see, plus a screenshot cropped to the relevant UI area for every visible change. Never a video: reviewers relate a failure to a step number (\\\"at step 3 I could not click X\\\"), which a video does not allow. A video is acceptable only when the interaction involves another program (drag and drop from a file manager, push to a word processor, ...) and the steps are still listed.\n5. Write keyboard shortcuts anywhere in the body with `<kbd>` tags: `<kbd>Ctrl</kbd> + <kbd>,</kbd>`, not `Ctrl+,`.\n6. Fill \\\"AI usage\\\": disclose every AI tool used **and the exact model ID** (for example `Claude Code (model claude-opus-4-7)`).\n7. Keep **all** checklist items. Mark each `[x]` (done), `[ ]` (TODO), or `[/]` (not applicable). Never `[ x]` or `[.]`.\n8. Remove **all** HTML comments before opening the PR.\n9. Write the body to a temp file and run `gh pr create --body-file <file>` — never `--body`, which bypasses the template.\n10. Only if the CHANGELOG.md entry used a `TODO` placeholder (meaning no issue has been confidently identified yet — an existing issue link always stays): create the PR with `--draft` (an automated review starts as soon as a PR is ready and would flag the placeholder), 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, then mark the PR ready (`gh pr ready <number>`). 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- Do not add an entry when fixing something that was itself introduced after the last release (e.g. a bug in a feature that only exists in `## [Unreleased]`) — users of the last release never saw the bug. Instead, update the existing unreleased entry if the fix changes what it should say.\n- The CHANGELOG.md entry should be for end users (and not programmers).\n- **One sentence, maximum 20 words.** No sub-bullets, no code blocks.\n- **Describe what changed for the user, never why or how it was implemented.** No class names, method names, or internals.\n- Start the entry with `We added` / `We changed` / `We fixed` / `We removed`, and place it under the matching `### Added` / `### Changed` / `### Fixed` / `### Removed` heading in `## [Unreleased]`.\n- Within the section, sort the entry in next to existing entries about the same component or feature (e.g. a jabkit fix goes next to the other jabkit fixes) instead of appending it at the end.\n- Do not add extra blank lines in CHANGELOG.md\n- Do not reorder or reword existing entries (except the unreleased entry your fix relates to, per the rule above), and do not create a new version heading.\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- Keyboard shortcuts in Markdown (CHANGELOG.md, `docs/`, PR descriptions, issue and review comments) use one `<kbd>` tag per key, first letter capitalized, keys joined by ` + ` (e.g. `<kbd>Ctrl</kbd> + <kbd>Enter</kbd>`).\n\n### CHANGELOG.md example\n\nGood:\n\n```markdown\n- We fixed an issue where the entry editor lost focus after saving a library. [#1234](https://github.com/JabRef/jabref/issues/1234)\n```\n\nBad — explains the implementation, names internals, too long:\n\n```markdown\n- We fixed a bug in the entry editor where, due to a race condition in the JavaFX\n  focus handling inside `EntryEditor#setFocus`, the focus was lost after the library\n  was saved. This was especially annoying for users who ... The fix introduces a\n  guard flag that ...\n```\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\nWhen adding a package or changing a package's or module's public surface, add or update its `package-info.java` / `module-info.java` Javadoc following [skills/developers/module-documentation/SKILL.md](skills/developers/module-documentation/SKILL.md).\n\nWhen adding or editing a `uses:` line in a workflow, follow [skills/developers/github-actions/SKILL.md](skills/developers/github-actions/SKILL.md) — external actions are pinned to a full commit SHA.\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",".cursor/mcp.json":"# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/JabRef/jabref/HEAD/.cursor/mcp.json)",".claude-plugin/marketplace.json":"# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/JabRef/jabref/HEAD/.claude-plugin/marketplace.json)",".claude-plugin/plugin.json":"# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/JabRef/jabref/HEAD/.claude-plugin/plugin.json)"},"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 instead of JavaDoc inline tags or HTML formatting tags: `` `code` `` instead of `{@code code}` or `<code>code</code>`, `[ClassName]` instead of `{@link ClassName}`, and fenced code blocks (```` ``` ````) instead of `<pre><code>`.\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- 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.\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- Deleting or renaming code orphans its keys, so run the test after such a change — and do not trust a green run you did not force. `LocalizationParser` walks `src/main/java` of every module (`jablib`, `jabkit`, `jabsrv`, `jabgui`, `jabls`) at test runtime, so those sources are not declared inputs of `:jablib:test`. The task is cacheable, and a `FROM-CACHE` or `UP-TO-DATE` result can hide a key that a deletion in another module just orphaned. Force it: `./gradlew :jablib:test --tests \"*LocalizationConsistencyTest*\" --rerun-tasks`\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 externalServicesTest` — hits live external APIs\n\nFetcher tests must always hit the live endpoints — do not mock or stub the remote API in fetcher tests.\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) (OFT) to trace requirements to implementation and tests.\nRequirements capture what JabRef should do as a structured representation of issues and features, enabling bidirectional traceability.\n\nFor a new feature or significant bug fix, add the requirement to the appropriate `docs/requirements/<area>.md` file.\n\nRead and use the [`openfasttrace`](https://github.com/itsallcode/openfasttrace-ai-skills/blob/main/skills/openfasttrace/SKILL.md) skill.\n\nIn JabRef we use OFT this way:\n\n- The requirements are put in `docs/requirements/<area>.md`.\n- The requirements are grouped by areas: `docs/requirements/ui.md`, `docs/requirements/git.md`, etc.\n- Title style:\n  - `req~` → **\"Subject must verb\"** (e.g., `## GitHub personal access token push access must be verifiable before sharing`).\n  - `feat~` → **\"User can verb\"** (e.g., `## User can share library via GitHub`).\n  - Avoid nominalizations: Write \"must be verified\" instead of \"verification\".\n  - One item, one requirement: If a title needs \"and\", split it into two separate requirements.\n  - The title carries the full normative statement: Anyone reading only the heading should understand the complete requirement constraint.\n- Use the description only for details that the title cannot carry:\n  - Triggering condition.\n  - Edge cases and boundary behavior.\n  - Brief rationale (if needed).\n  - Relevant GitHub issue link or context.\n\nArtifact types used:\n\n- `feat`: User-facing capability or broad feature (\"User can verb\").\n- `req`: Specific constraint, nuance, cross-cutting requirement, or bug fix the system must satisfy (\"Subject must verb\").\n- `impl`: Code implementation.\n- `utest`: Unit test.\n- `adr`: Architectural Decision Record.\n\n### Traceability chains\n\nIn JabRef, we use these traceability chains:\n\n- `feat` --> `impl`/`utest`\n- `req` --> `impl`/`utest`\n- `feat` --> `req` --> `impl`/`utest`\n- `adr` --> `impl`/`utest`\n\nAdditional guidelines:\n\n- Link the issue the requirement originates from (if there is).\n- Respect INVEST criteria. Prefer high-level requirements over overly detailed ones.\n- For ideas or planned requirements not yet implemented, mark them as draft so they are preserved without failing coverage checks: `Status: draft`.\n\nChecking coverage:\n\n```bash\n./gradlew traceRequirements   # output: build/reports/tracing.txt\n```\n\nSee `docs/requirements/` for existing requirements and [docs/code-howtos/requirements.md](docs/code-howtos/requirements.md) for full guidance. Also refer to the `openfasttrace` skill.\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\nTo link code to a decision, give the ADR an OpenFastTrace identifier directly below its title (no blank line in between)\nand declare what has to cover it:\n\n```markdown\n# Hardcode `StandardField` names\n`adr~hardcode-fieldnames~1`\n\nNeeds: impl\n```\n\n```java\n// [impl->adr~hardcode-fieldnames~1]\n```\n\nThe identifier's name part must not start with a digit, so drop the file's number prefix.\nAdd `<!-- markdownlint-disable-file MD022 -->` at the end of the ADR.\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- Before committing the merge, make sure no conflict marker is left: with `merge.conflictStyle=diff3` (the default here) a hunk has **four** markers — `<<<<<<<`, `|||||||` (the common-ancestor block), `=======`, `>>>>>>>` — and a resolution that only removes the outer ones leaves the ancestor block in the file. `git diff --cached --check` reports every leftover marker; run it after staging the resolved files.\n\n### Branches\n\n- `main` is the development branch; pull requests target it. `stable` is the last release plus ported fixes; CI labels a PR `dev: into-stable` when it links a bug issue (maintainers may add or remove the label by hand) and ports it after the merge. Never add that label to a port PR (`port-<number>-to-<branch>`). See [docs/contributing.md](docs/contributing.md#branching-strategy).\n\n### Commits\n\n- One logical change per commit\n- Clear, technical commit messages\n- Wrap annotations and other `@`-words in backticks in commit messages and PR texts (`` `@Nullable` ``); GitHub turns a plain `@Nullable` into a mention of that user\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. \\\"Steps to test\\\" is a numbered list of concrete steps ending in what the reviewer should see, plus a screenshot cropped to the relevant UI area for every visible change. Never a video: reviewers relate a failure to a step number (\\\"at step 3 I could not click X\\\"), which a video does not allow. A video is acceptable only when the interaction involves another program (drag and drop from a file manager, push to a word processor, ...) and the steps are still listed.\n5. Write keyboard shortcuts anywhere in the body with `<kbd>` tags: `<kbd>Ctrl</kbd> + <kbd>,</kbd>`, not `Ctrl+,`.\n6. Fill \\\"AI usage\\\": disclose every AI tool used **and the exact model ID** (for example `Claude Code (model claude-opus-4-7)`).\n7. Keep **all** checklist items. Mark each `[x]` (done), `[ ]` (TODO), or `[/]` (not applicable). Never `[ x]` or `[.]`.\n8. Remove **all** HTML comments before opening the PR.\n9. Write the body to a temp file and run `gh pr create --body-file <file>` — never `--body`, which bypasses the template.\n10. Only if the CHANGELOG.md entry used a `TODO` placeholder (meaning no issue has been confidently identified yet — an existing issue link always stays): create the PR with `--draft` (an automated review starts as soon as a PR is ready and would flag the placeholder), 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, then mark the PR ready (`gh pr ready <number>`). 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- Do not add an entry when fixing something that was itself introduced after the last release (e.g. a bug in a feature that only exists in `## [Unreleased]`) — users of the last release never saw the bug. Instead, update the existing unreleased entry if the fix changes what it should say.\n- The CHANGELOG.md entry should be for end users (and not programmers).\n- **One sentence, maximum 20 words.** No sub-bullets, no code blocks.\n- **Describe what changed for the user, never why or how it was implemented.** No class names, method names, or internals.\n- Start the entry with `We added` / `We changed` / `We fixed` / `We removed`, and place it under the matching `### Added` / `### Changed` / `### Fixed` / `### Removed` heading in `## [Unreleased]`.\n- Within the section, sort the entry in next to existing entries about the same component or feature (e.g. a jabkit fix goes next to the other jabkit fixes) instead of appending it at the end.\n- Do not add extra blank lines in CHANGELOG.md\n- Do not reorder or reword existing entries (except the unreleased entry your fix relates to, per the rule above), and do not create a new version heading.\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- Keyboard shortcuts in Markdown (CHANGELOG.md, `docs/`, PR descriptions, issue and review comments) use one `<kbd>` tag per key, first letter capitalized, keys joined by ` + ` (e.g. `<kbd>Ctrl</kbd> + <kbd>Enter</kbd>`).\n\n### CHANGELOG.md example\n\nGood:\n\n```markdown\n- We fixed an issue where the entry editor lost focus after saving a library. [#1234](https://github.com/JabRef/jabref/issues/1234)\n```\n\nBad — explains the implementation, names internals, too long:\n\n```markdown\n- We fixed a bug in the entry editor where, due to a race condition in the JavaFX\n  focus handling inside `EntryEditor#setFocus`, the focus was lost after the library\n  was saved. This was especially annoying for users who ... The fix introduces a\n  guard flag that ...\n```\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\nWhen adding a package or changing a package's or module's public surface, add or update its `package-info.java` / `module-info.java` Javadoc following [skills/developers/module-documentation/SKILL.md](skills/developers/module-documentation/SKILL.md).\n\nWhen adding or editing a `uses:` line in a workflow, follow [skills/developers/github-actions/SKILL.md](skills/developers/github-actions/SKILL.md) — external actions are pinned to a full commit SHA.\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",".cursor/mcp.json":"# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/JabRef/jabref/HEAD/.cursor/mcp.json)",".claude-plugin/marketplace.json":"# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/JabRef/jabref/HEAD/.claude-plugin/marketplace.json)",".claude-plugin/plugin.json":"# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/JabRef/jabref/HEAD/.claude-plugin/plugin.json)"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/JabRef/jabref/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","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 instead of JavaDoc inline tags or HTML formatting tags: `` `code` `` instead of `{@code code}` or `<code>code</code>`, `[ClassName]` instead of `{@link ClassName}`, and fenced code blocks (```` ``` ````) instead of `<pre><code>`.\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- 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.\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- Deleting or renaming code orphans its keys, so run the test after such a change — and do not trust a green run you did not force. `LocalizationParser` walks `src/main/java` of every module (`jablib`, `jabkit`, `jabsrv`, `jabgui`, `jabls`) at test runtime, so those sources are not declared inputs of `:jablib:test`. The task is cacheable, and a `FROM-CACHE` or `UP-TO-DATE` result can hide a key that a deletion in another module just orphaned. Force it: `./gradlew :jablib:test --tests \"*LocalizationConsistencyTest*\" --rerun-tasks`\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 externalServicesTest` — hits live external APIs\n\nFetcher tests must always hit the live endpoints — do not mock or stub the remote API in fetcher tests.\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) (OFT) to trace requirements to implementation and tests.\nRequirements capture what JabRef should do as a structured representation of issues and features, enabling bidirectional traceability.\n\nFor a new feature or significant bug fix, add the requirement to the appropriate `docs/requirements/<area>.md` file.\n\nRead and use the [`openfasttrace`](https://github.com/itsallcode/openfasttrace-ai-skills/blob/main/skills/openfasttrace/SKILL.md) skill.\n\nIn JabRef we use OFT this way:\n\n- The requirements are put in `docs/requirements/<area>.md`.\n- The requirements are grouped by areas: `docs/requirements/ui.md`, `docs/requirements/git.md`, etc.\n- Title style:\n  - `req~` → **\"Subject must verb\"** (e.g., `## GitHub personal access token push access must be verifiable before sharing`).\n  - `feat~` → **\"User can verb\"** (e.g., `## User can share library via GitHub`).\n  - Avoid nominalizations: Write \"must be verified\" instead of \"verification\".\n  - One item, one requirement: If a title needs \"and\", split it into two separate requirements.\n  - The title carries the full normative statement: Anyone reading only the heading should understand the complete requirement constraint.\n- Use the description only for details that the title cannot carry:\n  - Triggering condition.\n  - Edge cases and boundary behavior.\n  - Brief rationale (if needed).\n  - Relevant GitHub issue link or context.\n\nArtifact types used:\n\n- `feat`: User-facing capability or broad feature (\"User can verb\").\n- `req`: Specific constraint, nuance, cross-cutting requirement, or bug fix the system must satisfy (\"Subject must verb\").\n- `impl`: Code implementation.\n- `utest`: Unit test.\n- `adr`: Architectural Decision Record.\n\n### Traceability chains\n\nIn JabRef, we use these traceability chains:\n\n- `feat` --> `impl`/`utest`\n- `req` --> `impl`/`utest`\n- `feat` --> `req` --> `impl`/`utest`\n- `adr` --> `impl`/`utest`\n\nAdditional guidelines:\n\n- Link the issue the requirement originates from (if there is).\n- Respect INVEST criteria. Prefer high-level requirements over overly detailed ones.\n- For ideas or planned requirements not yet implemented, mark them as draft so they are preserved without failing coverage checks: `Status: draft`.\n\nChecking coverage:\n\n```bash\n./gradlew traceRequirements   # output: build/reports/tracing.txt\n```\n\nSee `docs/requirements/` for existing requirements and [docs/code-howtos/requirements.md](docs/code-howtos/requirements.md) for full guidance. Also refer to the `openfasttrace` skill.\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\nTo link code to a decision, give the ADR an OpenFastTrace identifier directly below its title (no blank line in between)\nand declare what has to cover it:\n\n```markdown\n# Hardcode `StandardField` names\n`adr~hardcode-fieldnames~1`\n\nNeeds: impl\n```\n\n```java\n// [impl->adr~hardcode-fieldnames~1]\n```\n\nThe identifier's name part must not start with a digit, so drop the file's number prefix.\nAdd `<!-- markdownlint-disable-file MD022 -->` at the end of the ADR.\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- Before committing the merge, make sure no conflict marker is left: with `merge.conflictStyle=diff3` (the default here) a hunk has **four** markers — `<<<<<<<`, `|||||||` (the common-ancestor block), `=======`, `>>>>>>>` — and a resolution that only removes the outer ones leaves the ancestor block in the file. `git diff --cached --check` reports every leftover marker; run it after staging the resolved files.\n\n### Branches\n\n- `main` is the development branch; pull requests target it. `stable` is the last release plus ported fixes; CI labels a PR `dev: into-stable` when it links a bug issue (maintainers may add or remove the label by hand) and ports it after the merge. Never add that label to a port PR (`port-<number>-to-<branch>`). See [docs/contributing.md](docs/contributing.md#branching-strategy).\n\n### Commits\n\n- One logical change per commit\n- Clear, technical commit messages\n- Wrap annotations and other `@`-words in backticks in commit messages and PR texts (`` `@Nullable` ``); GitHub turns a plain `@Nullable` into a mention of that user\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. \\\"Steps to test\\\" is a numbered list of concrete steps ending in what the reviewer should see, plus a screenshot cropped to the relevant UI area for every visible change. Never a video: reviewers relate a failure to a step number (\\\"at step 3 I could not click X\\\"), which a video does not allow. A video is acceptable only when the interaction involves another program (drag and drop from a file manager, push to a word processor, ...) and the steps are still listed.\n5. Write keyboard shortcuts anywhere in the body with `<kbd>` tags: `<kbd>Ctrl</kbd> + <kbd>,</kbd>`, not `Ctrl+,`.\n6. Fill \\\"AI usage\\\": disclose every AI tool used **and the exact model ID** (for example `Claude Code (model claude-opus-4-7)`).\n7. Keep **all** checklist items. Mark each `[x]` (done), `[ ]` (TODO), or `[/]` (not applicable). Never `[ x]` or `[.]`.\n8. Remove **all** HTML comments before opening the PR.\n9. Write the body to a temp file and run `gh pr create --body-file <file>` — never `--body`, which bypasses the template.\n10. Only if the CHANGELOG.md entry used a `TODO` placeholder (meaning no issue has been confidently identified yet — an existing issue link always stays): create the PR with `--draft` (an automated review starts as soon as a PR is ready and would flag the placeholder), 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, then mark the PR ready (`gh pr ready <number>`). 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- Do not add an entry when fixing something that was itself introduced after the last release (e.g. a bug in a feature that only exists in `## [Unreleased]`) — users of the last release never saw the bug. Instead, update the existing unreleased entry if the fix changes what it should say.\n- The CHANGELOG.md entry should be for end users (and not programmers).\n- **One sentence, maximum 20 words.** No sub-bullets, no code blocks.\n- **Describe what changed for the user, never why or how it was implemented.** No class names, method names, or internals.\n- Start the entry with `We added` / `We changed` / `We fixed` / `We removed`, and place it under the matching `### Added` / `### Changed` / `### Fixed` / `### Removed` heading in `## [Unreleased]`.\n- Within the section, sort the entry in next to existing entries about the same component or feature (e.g. a jabkit fix goes next to the other jabkit fixes) instead of appending it at the end.\n- Do not add extra blank lines in CHANGELOG.md\n- Do not reorder or reword existing entries (except the unreleased entry your fix relates to, per the rule above), and do not create a new version heading.\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- Keyboard shortcuts in Markdown (CHANGELOG.md, `docs/`, PR descriptions, issue and review comments) use one `<kbd>` tag per key, first letter capitalized, keys joined by ` + ` (e.g. `<kbd>Ctrl</kbd> + <kbd>Enter</kbd>`).\n\n### CHANGELOG.md example\n\nGood:\n\n```markdown\n- We fixed an issue where the entry editor lost focus after saving a library. [#1234](https://github.com/JabRef/jabref/issues/1234)\n```\n\nBad — explains the implementation, names internals, too long:\n\n```markdown\n- We fixed a bug in the entry editor where, due to a race condition in the JavaFX\n  focus handling inside `EntryEditor#setFocus`, the focus was lost after the library\n  was saved. This was especially annoying for users who ... The fix introduces a\n  guard flag that ...\n```\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\nWhen adding a package or changing a package's or module's public surface, add or update its `package-info.java` / `module-info.java` Javadoc following [skills/developers/module-documentation/SKILL.md](skills/developers/module-documentation/SKILL.md).\n\nWhen adding or editing a `uses:` line in a workflow, follow [skills/developers/github-actions/SKILL.md](skills/developers/github-actions/SKILL.md) — external actions are pinned to a full commit SHA.\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","isInternal":false,"tokens":6833,"sizeBytes":29089},{"name":"marketplace.json","path":".claude-plugin/marketplace.json","rawUrl":"https://raw.githubusercontent.com/JabRef/jabref/HEAD/.claude-plugin/marketplace.json","title":"Claude Plugin Marketplace Catalog","category":"marketplace","format":"json","content":"# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/JabRef/jabref/HEAD/.claude-plugin/marketplace.json)","tokens":300,"sizeBytes":192},{"name":"plugin.json","path":".claude-plugin/plugin.json","rawUrl":"https://raw.githubusercontent.com/JabRef/jabref/HEAD/.claude-plugin/plugin.json","title":"claude-plugin Plugin Manifest","category":"plugin-manifest","format":"json","content":"# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/JabRef/jabref/HEAD/.claude-plugin/plugin.json)","tokens":300,"sizeBytes":178},{"name":"mcp.json","path":".cursor/mcp.json","rawUrl":"https://raw.githubusercontent.com/JabRef/jabref/HEAD/.cursor/mcp.json","title":"Model Context Protocol (MCP) Configuration","category":"mcp-config","format":"json","content":"# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/JabRef/jabref/HEAD/.cursor/mcp.json)","tokens":300,"sizeBytes":171}],"systemPromptSnippet":"<yakaai_skills repo=\"JabRef/jabref\">\n<!-- File: AGENTS.md (Tokens: ~6833 | Category: root-instruction) -->\n## 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 instead of JavaDoc inline tags or HTML formatting tags: `` `code` `` instead of `{@code code}` or `<code>code</code>`, `[ClassName]` instead of `{@link ClassName}`, and fenced code blocks (```` ``` ````) instead of `<pre><code>`.\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- 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.\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- Deleting or renaming code orphans its keys, so run the test after such a change — and do not trust a green run you did not force. `LocalizationParser` walks `src/main/java` of every module (`jablib`, `jabkit`, `jabsrv`, `jabgui`, `jabls`) at test runtime, so those sources are not declared inputs of `:jablib:test`. The task is cacheable, and a `FROM-CACHE` or `UP-TO-DATE` result can hide a key that a deletion in another module just orphaned. Force it: `./gradlew :jablib:test --tests \"*LocalizationConsistencyTest*\" --rerun-tasks`\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 externalServicesTest` — hits live external APIs\n\nFetcher tests must always hit the live endpoints — do not mock or stub the remote API in fetcher tests.\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) (OFT) to trace requirements to implementation and tests.\nRequirements capture what JabRef should do as a structured representation of issues and features, enabling bidirectional traceability.\n\nFor a new feature or significant bug fix, add the requirement to the appropriate `docs/requirements/<area>.md` file.\n\nRead and use the [`openfasttrace`](https://github.com/itsallcode/openfasttrace-ai-skills/blob/main/skills/openfasttrace/SKILL.md) skill.\n\nIn JabRef we use OFT this way:\n\n- The requirements are put in `docs/requirements/<area>.md`.\n- The requirements are grouped by areas: `docs/requirements/ui.md`, `docs/requirements/git.md`, etc.\n- Title style:\n  - `req~` → **\"Subject must verb\"** (e.g., `## GitHub personal access token push access must be verifiable before sharing`).\n  - `feat~` → **\"User can verb\"** (e.g., `## User can share library via GitHub`).\n  - Avoid nominalizations: Write \"must be verified\" instead of \"verification\".\n  - One item, one requirement: If a title needs \"and\", split it into two separate requirements.\n  - The title carries the full normative statement: Anyone reading only the heading should understand the complete requirement constraint.\n- Use the description only for details that the title cannot carry:\n  - Triggering condition.\n  - Edge cases and boundary behavior.\n  - Brief rationale (if needed).\n  - Relevant GitHub issue link or context.\n\nArtifact types used:\n\n- `feat`: User-facing capability or broad feature (\"User can verb\").\n- `req`: Specific constraint, nuance, cross-cutting requirement, or bug fix the system must satisfy (\"Subject must verb\").\n- `impl`: Code implementation.\n- `utest`: Unit test.\n- `adr`: Architectural Decision Record.\n\n### Traceability chains\n\nIn JabRef, we use these traceability chains:\n\n- `feat` --> `impl`/`utest`\n- `req` --> `impl`/`utest`\n- `feat` --> `req` --> `impl`/`utest`\n- `adr` --> `impl`/`utest`\n\nAdditional guidelines:\n\n- Link the issue the requirement originates from (if there is).\n- Respect INVEST criteria. Prefer high-level requirements over overly detailed ones.\n- For ideas or planned requirements not yet implemented, mark them as draft so they are preserved without failing coverage checks: `Status: draft`.\n\nChecking coverage:\n\n```bash\n./gradlew traceRequirements   # output: build/reports/tracing.txt\n```\n\nSee `docs/requirements/` for existing requirements and [docs/code-howtos/requirements.md](docs/code-howtos/requirements.md) for full guidance. Also refer to the `openfasttrace` skill.\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\nTo link code to a decision, give the ADR an OpenFastTrace identifier directly below its title (no blank line in between)\nand declare what has to cover it:\n\n```markdown\n# Hardcode `StandardField` names\n`adr~hardcode-fieldnames~1`\n\nNeeds: impl\n```\n\n```java\n// [impl->adr~hardcode-fieldnames~1]\n```\n\nThe identifier's name part must not start with a digit, so drop the file's number prefix.\nAdd `<!-- markdownlint-disable-file MD022 -->` at the end of the ADR.\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- Before committing the merge, make sure no conflict marker is left: with `merge.conflictStyle=diff3` (the default here) a hunk has **four** markers — `<<<<<<<`, `|||||||` (the common-ancestor block), `=======`, `>>>>>>>` — and a resolution that only removes the outer ones leaves the ancestor block in the file. `git diff --cached --check` reports every leftover marker; run it after staging the resolved files.\n\n### Branches\n\n- `main` is the development branch; pull requests target it. `stable` is the last release plus ported fixes; CI labels a PR `dev: into-stable` when it links a bug issue (maintainers may add or remove the label by hand) and ports it after the merge. Never add that label to a port PR (`port-<number>-to-<branch>`). See [docs/contributing.md](docs/contributing.md#branching-strategy).\n\n### Commits\n\n- One logical change per commit\n- Clear, technical commit messages\n- Wrap annotations and other `@`-words in backticks in commit messages and PR texts (`` `@Nullable` ``); GitHub turns a plain `@Nullable` into a mention of that user\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. \\\"Steps to test\\\" is a numbered list of concrete steps ending in what the reviewer should see, plus a screenshot cropped to the relevant UI area for every visible change. Never a video: reviewers relate a failure to a step number (\\\"at step 3 I could not click X\\\"), which a video does not allow. A video is acceptable only when the interaction involves another program (drag and drop from a file manager, push to a word processor, ...) and the steps are still listed.\n5. Write keyboard shortcuts anywhere in the body with `<kbd>` tags: `<kbd>Ctrl</kbd> + <kbd>,</kbd>`, not `Ctrl+,`.\n6. Fill \\\"AI usage\\\": disclose every AI tool used **and the exact model ID** (for example `Claude Code (model claude-opus-4-7)`).\n7. Keep **all** checklist items. Mark each `[x]` (done), `[ ]` (TODO), or `[/]` (not applicable). Never `[ x]` or `[.]`.\n8. Remove **all** HTML comments before opening the PR.\n9. Write the body to a temp file and run `gh pr create --body-file <file>` — never `--body`, which bypasses the template.\n10. Only if the CHANGELOG.md entry used a `TODO` placeholder (meaning no issue has been confidently identified yet — an existing issue link always stays): create the PR with `--draft` (an automated review starts as soon as a PR is ready and would flag the placeholder), 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, then mark the PR ready (`gh pr ready <number>`). 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- Do not add an entry when fixing something that was itself introduced after the last release (e.g. a bug in a feature that only exists in `## [Unreleased]`) — users of the last release never saw the bug. Instead, update the existing unreleased entry if the fix changes what it should say.\n- The CHANGELOG.md entry should be for end users (and not programmers).\n- **One sentence, maximum 20 words.** No sub-bullets, no code blocks.\n- **Describe what changed for the user, never why or how it was implemented.** No class names, method names, or internals.\n- Start the entry with `We added` / `We changed` / `We fixed` / `We removed`, and place it under the matching `### Added` / `### Changed` / `### Fixed` / `### Removed` heading in `## [Unreleased]`.\n- Within the section, sort the entry in next to existing entries about the same component or feature (e.g. a jabkit fix goes next to the other jabkit fixes) instead of appending it at the end.\n- Do not add extra blank lines in CHANGELOG.md\n- Do not reorder or reword existing entries (except the unreleased entry your fix relates to, per the rule above), and do not create a new version heading.\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- Keyboard shortcuts in Markdown (CHANGELOG.md, `docs/`, PR descriptions, issue and review comments) use one `<kbd>` tag per key, first letter capitalized, keys joined by ` + ` (e.g. `<kbd>Ctrl</kbd> + <kbd>Enter</kbd>`).\n\n### CHANGELOG.md example\n\nGood:\n\n```markdown\n- We fixed an issue where the entry editor lost focus after saving a library. [#1234](https://github.com/JabRef/jabref/issues/1234)\n```\n\nBad — explains the implementation, names internals, too long:\n\n```markdown\n- We fixed a bug in the entry editor where, due to a race condition in the JavaFX\n  focus handling inside `EntryEditor#setFocus`, the focus was lost after the library\n  was saved. This was especially annoying for users who ... The fix introduces a\n  guard flag that ...\n```\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\nWhen adding a package or changing a package's or module's public surface, add or update its `package-info.java` / `module-info.java` Javadoc following [skills/developers/module-documentation/SKILL.md](skills/developers/module-documentation/SKILL.md).\n\nWhen adding or editing a `uses:` line in a workflow, follow [skills/developers/github-actions/SKILL.md](skills/developers/github-actions/SKILL.md) — external actions are pinned to a full commit SHA.\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\n<!-- File: .claude-plugin/marketplace.json (Tokens: ~300 | Category: marketplace) -->\n# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/JabRef/jabref/HEAD/.claude-plugin/marketplace.json)\n\n<!-- File: .claude-plugin/plugin.json (Tokens: ~300 | Category: plugin-manifest) -->\n# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/JabRef/jabref/HEAD/.claude-plugin/plugin.json)\n\n<!-- File: .cursor/mcp.json (Tokens: ~300 | Category: mcp-config) -->\n# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/JabRef/jabref/HEAD/.cursor/mcp.json)\n</yakaai_skills>"}