gravitee-api-management / gravitee-apim-distribution
AGENTS.md469 starsChanged 5 months agoApache-2.0View on GitHub
Root conventions also apply: read ../AGENTS.md; where they disagree, the closest file wins for its directory and below. If your tool cannot read it, restart it from the repository root. Java-specific conventions for Gravitee repositories. Global engineering, security, and TDD rules still apply. Treat changes to any of these as compatibility-sensitive — call them out explicitly in the PR description and final response summary: Run Maven here with -f gravitee-apim-distribution/pom.xml — see the two-reactor rule at the rep
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,542 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository31 other files it gives its agents.
- AGENTS.mdAGENTS.md
- .ai/AGENTS.mdAGENTS.md
- gravitee-apim-common/AGENTS.mdAGENTS.md
- gravitee-apim-console-webui/AGENTS.mdAGENTS.md
- gravitee-apim-definition/AGENTS.mdAGENTS.md
- gravitee-apim-gateway/AGENTS.mdAGENTS.md
- gravitee-apim-plugin/AGENTS.mdAGENTS.md
- gravitee-apim-portal-webui/AGENTS.mdAGENTS.md
- gravitee-apim-portal-webui-next/AGENTS.mdAGENTS.md
- gravitee-apim-reporter/AGENTS.mdAGENTS.md
- gravitee-apim-repository/AGENTS.mdAGENTS.md
- gravitee-apim-rest-api/AGENTS.mdAGENTS.md
- .ai/CLAUDE.mdCLAUDE.md
- CLAUDE.mdCLAUDE.md
- gravitee-apim-common/CLAUDE.mdCLAUDE.md
- gravitee-apim-console-webui/CLAUDE.mdCLAUDE.md
- gravitee-apim-definition/CLAUDE.mdCLAUDE.md
- gravitee-apim-distribution/CLAUDE.mdCLAUDE.md
- gravitee-apim-gateway/CLAUDE.mdCLAUDE.md
- gravitee-apim-plugin/CLAUDE.mdCLAUDE.md
- gravitee-apim-portal-webui/CLAUDE.mdCLAUDE.md
- gravitee-apim-portal-webui-next/CLAUDE.mdCLAUDE.md
- gravitee-apim-reporter/CLAUDE.mdCLAUDE.md
- gravitee-apim-repository/CLAUDE.mdCLAUDE.md
- gravitee-apim-rest-api/CLAUDE.mdCLAUDE.md
- .cursor/rules/graphene.mdCursor rule
- .cursor/rules/graphene-snippets/context-sidebar-detail-page.tsxCursor rule
- .cursor/rules/graphene-snippets/creation-wizard-page.tsxCursor rule
- .cursor/rules/graphene-snippets/data-table-list-page.tsxCursor rule
- .cursor/rules/graphene-snippets/json-schema-form-simple.tsxCursor rule
- .cursor/rules/graphene-snippets/json-schema-form-with-meta.tsxCursor rule
The file
We split this AGENTS.md into the rules it gives an agent
11 rules. About 0 are common, 6 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 19
Use the parent POM or BOM for dependency versions.
- Very specific: line 23
Use Lombok only where it is already conventional in the repo, such as an established logger annotation (@CustomLog in some repositories, …
- Distinctive: line 30
Never log an exception with a generic message: name the operation, the object, and its non-sensitive identifier (an entity or correlation …
- Distinctive: line 37
Use the repo's existing test stack.
- Very specific: line 38
Follow the repo's existing test naming style.
- Distinctive: line 39
Test behaviour at real boundaries — HTTP, messaging, persistence — rather than mocking entire frameworks for path-critical paths.
- Very specific: line 40
Keep tests deterministic. Avoid Thread.sleep, wall-clock assumptions, external network dependencies, and order-dependent assertions.
- Distinctive: line 42
When the build enforces a format check, run the repository's formatter before tests — a red format gate hides the real result.
- Distinctive: line 46
Treat changes to any of these as compatibility-sensitive — call them out explicitly in the PR description and final response summary:
- Very specific: line 57
Run Maven here with -f gravitee-apim-distribution/pom.xml — see the two-reactor rule at the repository root.
- Very specific: line 102
Jacoco is not in the chain: Never add @{argLine} to a surefire argument line: nothing defines the property, surefire passes the token …
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
<!--
Generated by gravitee-ai. Do not edit directly.
Edit the source rules and re-run: gbuddy setup
Source rules:
- context/rules/tech/java.md
- .ai/rules/apim-distribution-build.md
- .ai/rules/apim-java.md
-->Root conventions also apply: read ../AGENTS.md; where they disagree, the closest file wins for its directory and below. If your tool cannot read it, restart it from the repository root.
Java Conventions
Java-specific conventions for Gravitee repositories. Global engineering, security, and TDD rules still apply.
Follow the repo
- Match the repository's Java version, Maven setup, formatter, package structure, naming style, and test stack. Do not introduce a second convention.
- Use the parent POM or BOM for dependency versions. Avoid ad hoc version pins and avoid new dependencies when the repo already provides a suitable option.
Defaults when writing Java
- Use Lombok only where it is already conventional in the repo, such as an established logger annotation (
@CustomLogin some repositories,@Slf4jin others) or simple DTO/builders. Avoid introducing Lombok, especially broad annotations like@Data, where generated semantics are unclear. - On event-loop / non-blocking runtimes, never block the loop thread. Use the repo's existing async, worker, or blocking-execution pattern.
- Preserve architecture boundaries. If the repo uses hexagonal / clean / onion layering, keep domain and use-case code independent from infrastructure, framework, persistence, and transport details.
Errors and logging
- Log each failure once at the owning boundary: HTTP handler, CLI entry, scheduled job, worker, or message consumer. Lower layers wrap with context and rethrow; they do not duplicate the stack trace.
- Never log an exception with a generic message: name the operation, the object, and its non-sensitive identifier (an entity or correlation id).
- Reserve the error level for failures of the operation itself. Expected, gracefully handled exceptions — an authentication failure answered with a 401 — log at warn or info.
- A catch block is never empty: rethrow, or handle and log.
- Preserve cause chains internally; redact before exposure outward.
Testing
- Use the repo's existing test stack. In most Gravitee Java repos this means JUnit 5, AssertJ, and Mockito; use Testcontainers when boundary tests need real services and the repo already supports that pattern.
- Follow the repo's existing test naming style. Where no clear style exists, prefer
should_<behavior>[_when_<condition>]; group with@Nestedwhen it improves readability. - Test behaviour at real boundaries — HTTP, messaging, persistence — rather than mocking entire frameworks for path-critical paths.
- Keep tests deterministic. Avoid
Thread.sleep, wall-clock assumptions, external network dependencies, and order-dependent assertions. - In a multi-module Maven build, run from the repository root: build the module's upstream dependencies once with
mvn -pl <module> -am -DskipTests install, then run its tests withmvn -pl <module> test. Plain-am testruns every upstream module's tests too, and running Maven inside the child directory alone can fail with missing symbols. - When the build enforces a format check, run the repository's formatter before tests — a red format gate hides the real result.
Compatibility-sensitive surfaces
Treat changes to any of these as compatibility-sensitive — call them out explicitly in the PR description and final response summary:
- Public APIs: REST, gRPC, OpenAPI contracts, generated models.
- Persistence schemas: Liquibase changelogs, JPA entities, repository interfaces.
- Configuration keys, environment variables, and feature flags.
- Serialised DTOs, enum values, and on-wire formats.
- Authentication, authorisation, and security-relevant paths.
- Deployment files and CI configuration.
APIM Distribution Build
Run Maven here with -f gravitee-apim-distribution/pom.xml — see the two-reactor rule at the repository root.
Three flags, each of which fails quietly rather than loudly:
-Dapim.core.version=<root triplet>— without it you assemble the pinned released core instead of the working tree. The build succeeds and the change under test is simply absent.task build-distributioncomputes the value for you.-nsu— without it Maven may replace the engine you just installed with a timestamped snapshot from the remote. Same symptom, different route.-Dbundle=dev— picks the bundle-dev flavor (see below), and activates the profile adding the Cloud initializer and MCP libraries tolib/. That profile belongs to the gateway container, an external dependency here, so-Pdoes not reach it; only the property activation does.
Flavors: what a distribution ships
Each component is built in two steps, both in the package phase of gravitee-apim-distribution-standalone-{gateway,rest-api}:
- the assembly builds the slim distribution in
target/slim, from the dependencies declared outside any profile; - the
flavorgoal ofgravitee-apim-release-manifest-maven-plugincopies it totarget/distributionand adds the plugins its layer files name. Each flavor stacks layers offlavors/(<flavors>of the goal, ingravitee-apim-distribution-standalone/pom.xml).
| Build | Flavor | Layers | Ships |
no -Dbundle | community | community.txt | open-source plugins only |
-Dbundle | bundle-default | community.txt + enterprise.txt | the released zip and images |
-Dbundle=dev | bundle-dev | community.txt + enterprise.txt + dev.txt | our dev and test images |
- The flavors nest: community ⊂ bundle-default ⊂ bundle-dev. Each flavor stacks the layers of the smaller one and adds its own, so a name is written in one layer only.
Adding a plugin takes three edits:
- its version, in a property of
gravitee-apim-distribution/pom.xmlnamed after its artifactId (<gravitee-policy-foo.version>); - its declaration, with
<type>zip</type>and<scope>runtime</scope>, ingravitee-apim-distribution-standalone/pom.xml: outside any profile when every distribution ships it, otherwise in thecatalogprofile; - its artifactId in one layer: the one of the smallest flavor that ships it.
Declared in
catalogbut listed nowhere, it ships in no image: the release manifest still lists it, for custom images.- its version, in a property of
- Both components get every plugin their assembly accepts. The
pluginsdependencySet of eachplugin-assembly-distribution.xmlis an exclude list: a plugin meant for one component only is excluded from the other's assembly. Policies stay in both: the Management API loads them too. - Check where it landed. A name no component accepts, a typo included, is only logged as skipped (
not part of the catalog of <component>) and ships nowhere. After a build, look for the zip intarget/distribution/pluginsand intarget/release-manifest.jsonof each component. - The
catalogprofile is never activated.-Pcatalogwould put every plugin into the slim distribution, and so into every flavor. - One set of layers for both components. Each component takes the names its assembly accepts and logs the others as skipped: a typo shows up there, not as a failure.
target/distributionkeeps its path and its content: the Dockerfiles,task docker-backendand the CI read it as before.
Running the inference plugin on a Mac
The gravitee-inference-service zip bundled by default only ships the Linux ONNX Runtime natives, which is what the images need. To run the plugin natively on macOS, assemble with task build-distribution-macos, or pass -Dgravitee-inference-service.classifier=macos to the distribution build: it swaps in the macos zip, never both.
- Never for an image. A distribution assembled with the macOS zip packaged into a Linux image starts, then fails when the plugin loads.
task dockerrebuilds throughbuild-distribution, so it keeps the Linux zip; for a hand-madebuildximage, assemble the distribution without the property. - Never in
~/.m2/settings.xmlor the environment. The property is read by every distribution build, images included. Pass it per build.
What this reactor does not inherit
Its parent is io.gravitee:gravitee-parent, the organisation pom — not gravitee-apim-parent. That parent carries build conventions only: no dependencyManagement, no repositories, no dependencies. Anything the product parent supplied must be declared here explicitly.
- Jacoco is not in the chain. Never add
@{argLine}to a surefire argument line: nothing defines the property, surefire passes the token through literally, and the fork dies oncould not open '{argLine}'before a single test runs. - The integration suites need their
--add-opensflags insurefireArgLine; they reflect intojava.base. - Dependency versions come from one BOM import,
gravitee-apim-bom:${apim.core.version}.
Versions
Bundled plugin versions live in gravitee-apim-distribution/pom.xml — bumping one is a one-line change that does not touch the engine's build.
The two reactors carry their own <revision>/<sha1>/<changelist> and no longer have to agree. Which core the distribution assembles is decided by apim.core.version — its pin — or by the -Dapim.core.version a build passes, never by its own triplet.
The assembled distribution carries a core.version file at its root, filtered at assembly time, so what shipped can be read back from the bundle. The gateway and rest-api images publish the same value as the OCI label io.gravitee.core.version.
APIM Java Conventions
- Formatter: Google Java Style via the Maven Prettier plugin — run
mvn prettier:write -pl <module>on every module you changed. - Lombok — the shared Java rule's "already conventional" condition is met here: this codebase uses
@Data,@Builder, and@CustomLog; follow the module's existing conventions and inject loggers with@CustomLog, not@Slf4j. - Test method names are snake_case —
should_return_error_when_api_not_found()— the shared Java rule's "follow the repo's existing test naming style" resolved. - Gateway diagnostics: in reactive Gateway and plugin code, the
ctx.interruptWith()/ctx.warnWith()builder patterns are copy-ready in.ai/guides/gateway-diagnostics.md(a repository-root path).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

