Skip to main content
Agent-Agnostic Java Quality Guardrails: Put Standards in the Repo with AGENTS.md and Static Analysis
  1. Posts/

Agent-Agnostic Java Quality Guardrails: Put Standards in the Repo with AGENTS.md and Static Analysis

·2070 words·10 mins
NeatGuyCoding
Author
NeatGuyCoding
Table of Contents

Agent-Agnostic Java Quality Guardrails: Put Standards in the Repo with AGENTS.md and Static Analysis
#

Once a team rotates coding agents across GitHub Copilot, Windsurf, and Cursor, what breaks first is usually not model capability but which Markdown file holds the coding standards. Copilot recognizes .github/copilot-instructions.md, Windsurf promotes .windsurf/rules/*.md while also supporting AGENTS.md, and Claude Code defaults to CLAUDE.md—each product has its own filenames, and developers pay the synchronization cost.

A more durable approach is to converge the “README for agents” in the repo on the open AGENTS.md format, then use Checkstyle, SpotBugs, and ArchUnit in the Maven verify phase as a repeatable acceptance track. The former influences probabilistic compliance at generation time; the latter supplies objective evidence when the build fails. The sections below unpack the mechanics without treating violation counts from a single live demo as an industry benchmark (presenter’s view: the two-project comparison is an illustrative experiment only).

JavaOne 2026 session: Agent-Agnostic Guardrails with AGENTS.md and static analysis


Agent inconsistency: the problem is not the model but the lack of a single source of truth for standards
#

Why
#

Coding agent output is nondeterministic—the same prompt can drift across versions or vendors. If standards live only in chat memory or a private IDE config file, neither PR review nor CI can reference the same constraints.

Mechanism and constraints
#

Products differ on paths for “persistent instructions,” but the direction is the same: pull cross-session rules out of the prompt and into the repository. The talk frames this as instruction file fragmentation under agent churn—the pain is real, but Windsurf’s official path is .windsurf/rules/, not a colloquial root-level rules.md; a Codeium.md convention was not verified in public docs, so write-ups should follow each tool’s current documentation.

What to do
#

Choose AGENTS.md in version control as the cross-agent primary carrier; for tools that still only recognize vendor files, use thin wrappers that point at the same content (see Claude interoperability below).

Common pitfalls
#

  • Assuming a “stronger model” can replace a team standards document.
  • Treating manual copy-paste across three vendor Markdown files as a long-term strategy—it will inevitably lag code evolution.

Slide: The Problem — Agent Inconsistency, emphasizing inconsistent rule definitions across agents


AGENTS.md: a repo-bound open convention, not an IDE accessory
#

Why
#

Standards should travel with the Git repository, not with a subscription or desktop client, so Copilot agents, Windsurf Cascade, Cursor, and others read the same Markdown.

Mechanism and constraints
#

agents.md describes itself as A simple, open format for guiding coding agents; the FAQ is explicit: no mandatory schema—plain Markdown is enough. The Linux Foundation press release of 2025-12-09 announced the Agentic AI Foundation (AAIF), whose founding donated projects include MCP and AGENTS.md (OpenAI published in 2025-08 and donated in December). Precise wording should be “brought under AAIF,” not “merged with MCP into one project.”

GitHub Copilot documentation states that when multiple AGENTS.md files exist, the one nearest the edited file in the directory tree wins; an explicit prompt in the current chat can still override everything (agents.md FAQ).

What to do
#

Put global conventions at the repo root (build commands, logging, cross-cutting architecture); add layer-specific notes under controller/, service/, repository/, and similar paths so you do not stuff the entire codebase standard into context in one shot.

repo/
  AGENTS.md
  src/main/java/.../controller/AGENTS.md
  src/main/java/.../service/AGENTS.md
  src/main/java/.../repository/AGENTS.md

Common pitfalls
#

  • Treating AGENTS.md as a Copilot-only or single-vendor feature—many products already support it; Claude Code is the exception (next section).
  • Piling a “universal bible” at the root—this fights the “load what is nearby” mechanism.

IDE project tree: AGENTS.md under repository and service packages

In a layered Spring Boot project, you can write “Controllers call Services only” and “@Service classes must live in the .service package” into each layer’s AGENTS.md, and index them from the root file with section numbers (e.g. §2 architecture, §3 package placement). Then an agent editing BookService loads nearby guidance instead of the whole-repo spec. For monorepos, agents.md also recommends nested AGENTS.md—aligned with Copilot’s nearest-file-wins rule.

spring-boot-demo: ArchitectureTest alongside AGENTS.md directories, §3 package rules


AGENTS.md is only one layer in context—do not treat it as the entire context
#

Why
#

What an agent actually “sees” is a stack of information: system/vendor behavior, custom instructions, session history, implicit IDE context (open files, diffs), explicit @ references, and terminal/tool output. Presenter’s view: AGENTS.md is a small slice of the custom instructions layer; ignoring the other layers still leads to drift in longer sessions.

Mechanism and constraints
#

Mermaid diagram 1

Each product trims and tokenizes layers differently—there is no cross-vendor “context engineering” spec. In practice, inject only standards relevant to the current task (e.g. prefer service/AGENTS.md when changing BookService).

What to do
#

  • Global AGENTS.md: build/test, DoD, and ArchUnit index readable in under two screens.
  • Per-layer files: only that package’s API/layering rules.
  • State in the DoD that changes must run ./mvnw verify so tool output enters the feedback layer.

Common pitfalls
#

  • Assuming AGENTS.md alone means 100% compliance (presenter’s rough estimate ~80–90%, no official statistic).
  • Repeating long standards in chat while the same text lives in files—duplicating context usage.

Slide: Context Window — Custom Instructions layer annotated with AGENTS.md


Writing AGENTS.md: stay concise, iterate, and put the DoD in the Definition of Done
#

Why
#

No schema does not mean unlimited length. agents.md allows any headings, but overlong files or agent-common knowledge crowd out useful context (presenter’s view: citing recent papers that auto-generated or verbose instructions hurt generation quality—the paper title was not given in the materials, not independently verified).

Mechanism and constraints
#

Suggested sections (all optional): project overview, build/test commands such as ./mvnw verify, code-style pointers (to Checkstyle config), architecture rules (manually aligned with ArchUnit rule section numbers—tools do not parse § 2), security highlights.

What to do
#

## Definition of Done
- Run `./mvnw verify` after code changes.
- Fix all Checkstyle, SpotBugs, and ArchUnit failures before finishing the task.
- Layering rules: see service/AGENTS.md; Controllers must not call Repository directly (AGENTS.md §2).

Maven documentation: the verify phase is appropriate for integration tests and additional checks (e.g. Checkstyle bound to this phase).

Common pitfalls
#

  • Tabulating Java naming conventions Checkstyle already enforces.
  • Expecting ArchUnit and Markdown section numbers to “link automatically”—because("… AGENTS.md §2") is only a description string; it does not create a machine link.

Demo: Plan step and Run ./mvnw verify to enforce quality checks


Dual-track guardrails: shift instructions left + static analysis acceptance
#

Why
#

Documented standards that never become BUILD FAILURE still slip into main; human review is slow and subjective. The slides summarize: AGENTS.md defines standards; static tools enforce them.

Mechanism and constraints
#

Mermaid diagram 2

  • Left track (probabilistic): the agent reads AGENTS.md / discovers existing pom.xml plugins and tends to generate against existing gates (presenter’s view: “most of the time” even when the user does not mention Checkstyle in the prompt).
  • Right track (deterministic): the maven-checkstyle-plugin check goal defaults to the verify phase; failOnViolation defaults to true (check Mojo documentation).

Compared with SonarQube: qualitativelySonarScanner needs SONAR_HOST_URL and other settings to talk to a server; the local Maven plugin path fits agent fast-feedback loops better. Sonar also has a Community Build for local deployment, so it is inaccurate to say “Sonar always requires external SaaS.”

What to do
#

pom.xml snippet (demo OCR showed 3.3.1; the plugin site has newer releases—the coordinate family is what matters):

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-checkstyle-plugin</artifactId>
  <version>3.3.1</version>
  <executions>
    <execution>
      <id>checkstyle-validate</id>
      <phase>verify</phase>
      <goals><goal>check</goal></goals>
    </execution>
  </executions>
</plugin>

Common pitfalls
#

  • Running only mvn compile—checks bound to verify are skipped.
  • Expecting Sonar or Checkstyle alone to cover architecture layering—ArchUnit expresses different constraints (next section).

Slide: AGENTS.md defines standards; static analysis tools enforce them


Checkstyle: pin style and import rules at build time
#

Why
#

Without rules, agent-generated code often shows tabs, AvoidStarImport, missing blank lines, and similar issues—annoying in review and better failed in CI.

Mechanism and constraints
#

Checkstyle inspects source style; common modules include AvoidStarImport, FileTabCharacter, and EmptyLineSeparator.

What to do
#

Locally or via an agent:

./mvnw verify

On failure, logs show maven-checkstyle-plugin:check (checkstyle-validate) with line numbers; paste output back into the agent for iteration.

Common pitfalls
#

  • Equating “compiles” with “matches team style.”
  • Adding Checkstyle after the fact to a legacy codebase and expecting zero churn—the demo-projects tree without AGENTS.md still had many violations after plugins were added (live build output, not a universal benchmark).

Maven build failure: checkstyle-validate failed in verify phase

Checkstyle report: AvoidStarImport and related violations in file containing BookService.updateBook

Unguarded demo: BookService.updateBook and integration test context


SpotBugs and ArchUnit: beyond style—for defects and layering
#

Why
#

Checkstyle does not cover NPE risk, resource leaks, or concurrency; package structure and rules like “Controller must not call Repository directly” are not expressible as style checks. The demo roadmap groups the three tools: Checkstyle for “does it look right,” SpotBugs for “will it blow up at runtime,” ArchUnit for “is the structure allowed”—presenter’s synthesis, but each tool’s official positioning supports the split.

Agenda excerpt: Checkstyle · SpotBugs · ArchUnit and the agent feedback loop

Mechanism and constraints
#

  • SpotBugs: finds bug patterns on bytecode; the Maven check goal can fail the build (SpotBugs Maven documentation). The check goal name matches Checkstyle’s but is a different plugin—use distinct execution ids when both bind to verify.
  • ArchUnit: express architecture rules in src/test with JUnit; @AnalyzeClasses + @ArchTest align with the User Guide APIs such as resideInAPackage and layeredArchitecture.

What to do
#

SpotBugs in pom.xml is typically bound to verify via spotbugs-maven-plugin’s check goal (see the official sample POM). Local verification:

./mvnw verify -DskipTests=false

ArchUnit example (consistent with OCR showing ClassFileImporter and Service.class):

@AnalyzeClasses(packages = "javaone.demo",
    importOptions = ImportOption.DoNotIncludeTests.class)
class ArchitectureTest {
  @ArchTest
  static final ArchRule servicesInServicePkg = classes()
    .that().areAnnotatedWith(Service.class)
    .should().resideInAPackage("..service..");

  @ArchTest
  static final ArchRule noControllerToRepo = noClasses()
    .that().resideInAPackage("..controller..")
    .should().accessClassesThat().resideInAPackage("..repository..")
    .because("Controllers must not access repositories directly (AGENTS.md § 2)");
}

OCR shows areAnnotatedWith(Service.class) cross-referenced with AGENTS.md §—the team must keep Markdown and tests in sync manually.

Common pitfalls
#

  • Writing “Controllers must not access Repositories” in AGENTS.md without ArchUnit—the agent may still generate cross-layer calls.
  • Treating ArchUnit as runtime AOP—it is a test-phase assertion, run by default with test inside verify.

ArchitectureTest: @Service classes must reside in service package (AGENTS.md §3)


Closed loop: mvn verify drives agent self-repair
#

Why
#

Standards in the DoD are useless if commands are not run—the agent may still submit red builds; when IDE agent mode (Copilot agent, Windsurf Plan, etc.) can run a terminal, violations can feed the next prompt.

Mechanism and constraints
#

mvn verify runs through the verify phase, aggregating Checkstyle, SpotBugs, and Surefire (including ArchUnit tests). A non-zero exit code is a hard failure—regardless of whether the agent “understood.”

What to do
#

  1. Put ./mvnw verify in the root AGENTS.md DoD.
  2. Have the agent read terminal output at task end and fix until green.
  3. When switching agents, standards files need not change—the demo used Windsurf Pre-Release and Copilot against the same BookService codebase (presenter’s view: Claude does not read AGENTS.md natively; interoperability is required).

Official Claude Code approach (prefer over unofficial hacks): @AGENTS.md import in CLAUDE.md, or ln -s AGENTS.md CLAUDE.md (on Windows, prefer import).

# CLAUDE.md
@AGENTS.md

Common pitfalls
#

  • Assuming the agent will always run Maven automatically—depends on product, permissions, and how explicit the DoD is (product behavior, not a Maven spec).
  • Writing verify once in the prompt but not anchoring it in AGENTS.md—lost on the next session.

Windsurf Pre-Release editing BookService.deleteBook, multi-agent demo


Implementation checklist: from fragmented instructions to a verifiable repository
#

StepAction
1Replace multiple vendor rule files with root AGENTS.md; use @AGENTS.md for Claude
2Nest AGENTS.md by package layer; follow nearest wins
3Bind Checkstyle / SpotBugs / ArchUnit to verify in pom.xml
4DoD requires ./mvnw verify + fix all failures
5Manually align ArchUnit because(...) with AGENTS.md section numbers
6Use the same verify in CI and locally to avoid “green locally, red in pipeline”

Three benefits (presenter’s summary, matching slides): Agent Independence—switch tools, same standard; Build Accountability—cannot call work done without passing gates; Team Confidence—review can focus on business logic. The guarded spring-boot-demo read per-layer AGENTS.md before generating in agent mode and produced cross-cutting pieces such as GlobalExceptionHandler; demo-projects without AGENTS.md, generated by Junie, lacked unified exception handling and documented comments—the direction matches the mechanism, but class names and violation counts are demo-specific and should not be extrapolated as industry statistics.

Slide: Key Benefits — Agent Independence, Build Accountability, Team Confidence

Full checkstyle.xml, SpotBugs include filters, and demo repository URLs were not provided in full in public materials; in production, start from the team’s existing Checkstyle config or Google/Java community rule sets, then tighten gradually.


References and further reading
#

Related