Contributing to Vidocq

How to contribute to the Vidocq ecosystem — CLA, GPG signing, conventions, and workflow.

Vidocq welcomes contributions at every layer of the stack: bug reports, TCK coverage improvements, new specification implementations, performance work, and documentation.

The source code is hosted under the Vidocq organisation on Codeberg. Each specification implementation lives in its own repository.

Before You Start

Two things are required before any code contribution can be accepted. Both are non-negotiable: they protect you, other contributors, and the users of the project.

1. GPG-signed commits

Every commit must be cryptographically signed with your GPG key. The CI workflow verifies this automatically on every pull request.

If you are new to GPG:

Generate a key, configure Git to sign all commits, and add your public key to your Codeberg account:

# Generate an ed25519 key
gpg --batch --gen-key <<EOF
Key-Type: ECDSA
Key-Curve: ed25519
Subkey-Type: ECDH
Subkey-Curve: cv25519
Name-Real: Your Full Name
Name-Email: your@email.com
Expire-Date: 2y
%ask-passphrase
EOF

# Find your key ID, then configure git
gpg --list-secret-keys --keyid-format=long your@email.com
git config --global user.signingkey KEY_ID
git config --global commit.gpgsign true
git config --global tag.gpgsign true

# Automatically append Signed-off-by to every commit
git config --local format.signoff true

Export your public key and add it under Settings → SSH/GPG Keys in your Codeberg profile:

gpg --export --armor your@email.com

2. Contributor License Agreement (CLA)

Vidocq uses a Contributor License Agreement (CLA v1.0) combined with the Developer Certificate of Origin (DCO 1.1) on every commit.

The CLA covers the project’s disjunctive triple licence:

SPDX-License-Identifier: EPL-2.0 OR EUPL-1.2 OR GPL-2.0-or-later

To sign the CLA, open a dedicated pull request (separate from your first code contribution) against the Vidocq governance repository:

  1. Read CLA.md carefully.

  2. Add a row with your full name, Codeberg username, and today’s date to CLA-signatures/individuals.md.

  3. Add your exported GPG public key as .forgejo/keys/<your-username>.asc (this file enables automated signature verification on future pull requests).

  4. Include the following statement verbatim in the pull request description:

    I have read and agree to the Vidocq Contributor License Agreement v1.0.

Corporate contributors: contact the maintainers before submitting anything. Once your CLA pull request is merged, your code contributions can be reviewed.

Development Setup

All sub-projects pin their toolchain via .sdkmanrc. Install SDKMAN!, then from any sub-project root:

sdk env

This installs and activates:

  • Java 25 (Temurin) — required by all sub-projects.

  • Maven 3.9.16 — pinned via .sdkmanrc; Maven 4 is not yet supported.

The workspace is a flat collection of independent Maven reactors — there is no root POM. Always cd into the sub-project you intend to work on:

cd chappe
./mvnw -ntp install -DskipTests   # full build
./mvnw test                        # unit tests only

Code Conventions

These rules apply to every sub-project unless an explicit exception is documented in that sub-project’s CLAUDE.md.

JPMS — strict module boundaries

  • Every module ships a module-info.java.

  • exports are minimal: only packages that form the public API.

  • opens require a documented reason (reflective access for CDI is the only accepted case).

  • No classpath mode, no automatic modules, no split packages.

Zero external dependencies

Production scope may only contain Jakarta or MicroProfile specification artifacts. No ASM, Byte Buddy, reflection libraries, or general-purpose utilities. Any new runtime dependency requires explicit justification in the pull request.

Maximum static code generation

Prefer the Class-File API (JEP 484) and APT annotation processors over runtime reflection. Metadata that can be produced at compile or process-classes time must not be computed at runtime. This keeps startup time flat and makes native compilation with GraalVM and Leyden CDS straightforward.

Virtual threads for all I/O

Use Executors.newVirtualThreadPerTaskExecutor() for any I/O path. Platform thread pools are only acceptable with a documented reason. Avoid synchronized blocks around I/O; prefer ReentrantLock to prevent carrier-thread pinning.

Test-driven development

Write the failing test before the implementation — red → green → refactor. For official specification tests, use the Jakarta TCK via Arquillian before writing custom tests.

TCK runners

TCK runners are intentionally excluded from their parent reactor because ShrinkWrap 3.3 is incompatible with Maven Model 4.1.0. Always run TCKs via the provided shell script from the sub-project root:

cassini/run-official-tck-restful-4.0.sh
foy/run-official-tck-servlet6.1.sh
champollion/run-official-tck-jsonp-2.1.sh

Submitting a Contribution

  1. Fork the relevant repository on Codeberg.

  2. Create a feature branch from main:

    git checkout -b feat/your-feature-name
  3. Write the failing test first, then the implementation.

  4. Verify the full build: ./mvnw verify.

  5. If your change touches a Jakarta TCK, run the relevant script and confirm no regression.

  6. Push and open a pull request against main.

Commit message format

Vidocq uses Conventional Commits:

<type>(<scope>): <short description>

[optional body]

Signed-off-by: Your Name <your@email.com>

Types: feat, fix, docs, refactor, test, chore, perf

Scopes: module names — chappe, vauban, champollion, ravel, cassini, foy, …​

feat(chappe): add HTTP/2 push promise support

Implements server push as defined in RFC 9113 § 8.4.
Closes #42.

Signed-off-by: Jane Doe <jane.doe@example.com>

Bug Reports and Performance Changes

Any reproducible bug must be tracked in a BUG.md file at the root of the relevant sub-project: short id, date, symptom, minimal repro, root-cause hypothesis, and status. Include a BUG.md entry in your pull request if you are fixing a known bug.

Any performance number must be recorded in a BENCH.md file at the sub-project root: date, hardware and JVM details, exact command, raw results, and delta versus the previous run. Never quote performance figures in commit messages or PR descriptions without a BENCH.md entry.

Language

Commit messages, Javadoc, and all .md and .adoc files must be written in English.