# Contributing to Spring AI Spring AI is released under the Apache 2.0 license. If you would like to contribute something, or want to hack on the code, this document should help you get started. ## Code of Conduct This project adheres to the Contributor Covenant [code of conduct](https://github.com/spring-projects/spring-ai#coc-ov-file). By participating, you are expected to uphold this code. Please report unacceptable behavior to code-of-conduct@spring.io. **We accept contributions created with the help of AI coding agents, but they must be carefully reviewed by a human who remains accountable for the quality of the contribution.** Contributions submitted by GitHub accounts controlled by autonomous AI bots are forbidden and will result in permanent bans. ## Reporting Security Vulnerabilities If you think you have found a security vulnerability in Spring AI please **DO NOT** disclose it publicly until we've had a chance to fix it. Please don't report security vulnerabilities using GitHub issues or pull requests, instead head over to https://spring.io/security-policy and learn how to disclose them responsibly. ## Ask questions If you have a question, check Stack Overflow using [this list of tags](https://stackoverflow.com/questions/tagged/spring-ai) or [Spring AI discussions](https://github.com/spring-projects/spring-ai/discussions). Find an existing discussion, or start a new one if necessary. ## How to contribute ### Search first Is there already an existing [issue](https://github.com/spring-projects/spring-ai/issues) or a [pull request](https://github.com/spring-projects/spring-ai/pulls) that addresses your concern? Search to see if you can find something similar before creating a new one. ### Submit an issue If you are reporting a bug, please help to speed up problem diagnosis by providing as much information as possible. Ideally, that would include a small sample project that reproduces the problem, shared with a link to a related source repository or attached as an archive with instructions on how to reproduce. You can also submit an enhancement or a new feature proposal. The issue title is used to generate the changelog so please use a short and descriptive text with types or filenames enclosed in backticks. ### Submit a pull request Should you create an issue first? No, just create the pull request and use the description to provide context and motivation, as you would for an issue. You only have to create an issue if you want to start a discussion first. Please don't submit pull requests: * With GitHub accounts managed by autonomous AI bots * For already assigned issues (as the assignee is or plans to work on it) * For straightforward or polish-style changes The pull request title is used to generate the changelog so please use a short and descriptive text with types or filenames enclosed in backticks. If your pull request is related to an issue, please mention the related issue with its number in the PR description (not in the title), for example "Fixes #123". Before submitting a pull request: * Add new tests that exercise the code you have added or modified * Run the build and tests locally with `./mvnw clean package` * If possible run integration tests related to the part you modify (see related documentation below) * Any code needs to be carefully reviewed by a human, especially when generated by a coding agent ## Commit message A commit message should include a short title (if possible less than 50 characters) starting with an uppercase verb. The title should *not* include prefixes like `fix:`, `feat:` or `docs:` or the issue/PR number. - ✅ Add Contribution Guidelines - ❌ GH-123: Add Contribution Guidelines - ❌ docs: Add Contribution Guidelines - ❌ Add Contribution Guidelines (#123) The commit description should be wrapped at approximately 72 characters. Commit messages should allow discoverability of related issues and PRs [by linking them](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) after the description with for example `Closes #123` if the issue number is 123. That allows bi-directional navigation from the commit to the issue/PR, but also in the other way around as related mentions are added by GitHub. All commits must include a __Signed-off-by__ trailer at the end of each commit message to indicate that the contributor agrees to the Developer Certificate of Origin. For additional details, please refer to the blog post [Hello DCO, Goodbye CLA: Simplifying Contributions to Spring](https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring). Please find below the example of a typical commit message: ```text Add Contribution Guidelines This commit adds CONTRIBUTING.md describing the Contribution procedure, mentions Contribution Guidelines in the README.md and mentions CODE_OF_CONDUCT in the README.md. Fixes #123 Signed-off-by: Firstname Lastname ``` If you want to only reference some issue or PR without closing it, you can use `See #123`. Annotations should be enclosed in backticks to avoid mentioning potential related GitHub users. If the commit has both an issue and a PR associated, the Spring AI committer merging the PR should reference both the issue and the PR and ensure the title does not contain the number of the PR, for example with an issue #123 and a PR #456: ```text Add Contribution Guidelines ... Fixes #123 Closes #456 Signed-off-by: Firstname Lastname ``` ## Source code style Spring AI source code style follows the checkstyle guidelines used by the [core Spring Framework project](https://github.com/spring-projects/spring-framework/wiki/Code-Style) with some exceptions. See also related [IntelliJ IDEA Editor Settings](https://github.com/spring-projects/spring-framework/blob/main/src/idea/spring-framework.xml). The code is formatted using the [java-format plugin](https://github.com/spring-io/spring-javaformat) as part of the build. Correct formatting is enforced by CI. To format the code specifically: ```shell ./mvnw process-sources ``` Note that this will not format the import order which is documented below. ### Formatting Please carefully follow the whitespace and formatting conventions already present in the framework. * UTF-8 encoding * Tabs, not spaces * Unix (LF), not DOS (CRLF) line endings * Eliminate all trailing whitespace * Wrap Javadoc at 90 characters * Aim to wrap code at 120 characters, but favor readability over wrapping * Preserve existing formatting; i.e. do not reformat code for its own sake * For plain text documents like `.adoc` or `.md`, one sentence per line The import statements are structured as follows: * import `java.*` * blank line * import `javax.*` * import `jakarta.*` * blank line * import all other imports * blank line * import `org.springframework.*` * blank line * import static all other imports Static imports should not be used in production code, but they should be used in test code, especially for things like `import static org.assertj.core.api.Assertions.assertThat;`. Although static imports are generally forbidden in production code, the following are use cases for which static imports are permissible. * constants (including enum constants): such as those in `java.nio.charset.StandardCharsets` or `org.springframework.core.annotation.MergedAnnotations.SearchStrategy` * static factory methods for third-party DSLs: such as the methods in `org.junit.platform.engine.discovery.DiscoverySelectors` when used with the JUnit Platform `Launcher` API Wildcard imports such as `import java.util.*` or `import static org.assertj.core.api.Assertions.*` are forbidden, even in test code. ### Source file structure A source file consists of the following, in this exact order: * License * Package statement * Import statements * Exactly one top-level class Exactly one blank line separates each of the above sections. #### License ```java /* * Copyright 2023-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ ``` #### `@since` tags Use `@since` tags for newly-added public API types and methods e.g. ```java /** * ... * * @since 2.0.0 */ ``` ### Working with the code #### Building from source The project can be built from the root directory using the standard Maven command: ```shell ./mvnw clean package ``` ##### JDK The project targets and builds artifacts compatible with Java 17+, and requires a JDK with support for the [`-XDaddTypeAnnotationsToSymbol` javac argument](https://bugs.openjdk.org/browse/JDK-8373586), like Liberica 17.0.19+, for nullability checks. The recommended JDK is specified in the `.sdkmanrc` file, which can be installed and configured with the [SDKMAN!](https://sdkman.io/) tool: - `sdk env install` to install the related JDK locally - `sdk env` to use the related JDK **NOTE:** Make sure to use a JDK with the same architecture as your processor, not an emulated one (for example with Rosetta on Mac) as Spring AI requires components that depend on your specific CPU architecture (PyTorch for example). If you are unsure if you have the correct JDK distribution for your CPU, run the command `java -XshowSettings:properties -version 2>&1 | grep os.arch` to validate that it matches your machine. ##### Maven build-cache extension The [Maven build-cache extension](https://maven.apache.org/extensions/maven-build-cache-extension/) is enabled by default to speedup builds. If you suspect the build cache is in an invalid state (build broken for no identified reason), try to run the build while disabling the build cache, for example with: ```shell ./mvnw -Dmaven.build.cache.enabled=false clean package ``` If the build passes without the cache, please [file an issue](https://github.com/spring-projects/spring-ai/issues) describing with as much detail as possible how that happened, and remove the local cache as a workaround: ```shell rm -rf ~/.m2/build-cache/ ``` #### Integration Tests There are many integration tests, so it often isn't realistic to run them all at once. Note that you should set API key environment variables for model providers before running. If the API key isn't set for a specific model provider, the integration test is skipped. To run the integration test for a specific module: ```shell ./mvnw -am -pl spring-ai-spring-boot-testcontainers -Pintegration-tests verify ``` To run a specific integration test allowing for up to two attempts to succeed (this is useful when a hosted service is not reliable or times out): ```shell ./mvnw -am -pl vector-stores/spring-ai-pgvector-store -Pintegration-tests -Dfailsafe.failIfNoSpecifiedTests=false -Dfailsafe.rerunFailingTestsCount=2 -Dit.test=PgVectorStoreIT verify ``` A quick pass through the most important pathways that runs integration tests can be done with the profile `-Pci-fast-integration-tests` and is used in the main CI build of this project. Full integration tests are done regularly in the [Spring AI Integration Tests](https://github.com/spring-projects/spring-ai-integration-tests) repository. #### Javadocs To check javadocs using the [javadoc:javadoc](https://maven.apache.org/plugins/maven-javadoc-plugin/): ```shell ./mvnw javadoc:javadoc ``` #### Reference documentation To build the docs: ```shell ./mvnw -pl spring-ai-docs antora ``` The generated documentation is available at `spring-ai-docs/target/antora/site/index.html`.