<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Peng Zhou</title>
    <description>The latest articles on DEV Community by Peng Zhou (@pengzhou).</description>
    <link>https://dev.to/pengzhou</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4198131%2F571f4e2c-f5d3-4435-8938-af565f97b3af.png</url>
      <title>DEV Community: Peng Zhou</title>
      <link>https://dev.to/pengzhou</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pengzhou"/>
    <language>en</language>
    <item>
      <title>What I Learned Running OpenAI Codex on a Real Spring Boot Codebase</title>
      <dc:creator>Peng Zhou</dc:creator>
      <pubDate>Wed, 21 Oct 2026 10:57:54 +0000</pubDate>
      <link>https://dev.to/pengzhou/what-i-learned-running-openai-codex-on-a-real-spring-boot-codebase-4eaa</link>
      <guid>https://dev.to/pengzhou/what-i-learned-running-openai-codex-on-a-real-spring-boot-codebase-4eaa</guid>
      <description>&lt;p&gt;Most "I tried Codex on Java" posts use a greenfield todo app. I did the opposite: a Spring Boot monorepo with a real domain model, MapStruct mappers, a Flyway migration history, and a test suite that already existed before the agent showed up.&lt;/p&gt;

&lt;p&gt;I ran it for a couple of weeks. What surprised me wasn't where it failed — it was where it &lt;em&gt;looked&lt;/em&gt; finished and wasn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Codex and Claude Code are different shapes
&lt;/h2&gt;

&lt;p&gt;The first thing to internalise is that "Codex" is two products wearing one name: the open-source CLI in your terminal, and Codex Cloud, the async agent you trigger from a dashboard or by tagging &lt;code&gt;@codex&lt;/code&gt; on a GitHub issue.&lt;/p&gt;

&lt;p&gt;The mindset gap with Claude Code matters more than the feature gap. Claude Code is interactive — you watch it work and approve the risky steps as they arrive. Codex is built for delegation. You describe a task, walk away, and come back to a diff or a PR. I queue three small tasks, close the laptop, and review after dinner. You don't babysit Codex the way you babysit Claude Code, and you can't fire-and-forget Claude Code the same way. That split is the whole reason I keep both installed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one line in AGENTS.md that pays for itself
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;AGENTS.md&lt;/code&gt; is Codex's project-instructions file — the twin of Claude Code's &lt;code&gt;CLAUDE.md&lt;/code&gt;. Codex offers to draft one on first run; let it, then throw half away, exactly like &lt;code&gt;/init&lt;/code&gt;. Generated instruction files guess at conventions they can't know.&lt;/p&gt;

&lt;p&gt;Here's close to what I actually run on a Spring Boot / Java 21 / Maven app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Project&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Spring Boot, Java 21, Maven. Use the wrapper: &lt;span class="sb"&gt;`./mvnw`&lt;/span&gt;.
&lt;span class="p"&gt;-&lt;/span&gt; Layering: controller -&amp;gt; service -&amp;gt; repository. No business logic in controllers.
&lt;span class="p"&gt;-&lt;/span&gt; MapStruct for DTO mapping. Constructor injection only.

&lt;span class="gu"&gt;## Conventions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Records for read DTOs. Validation in the DTO via Bean Validation, not the service.
&lt;span class="p"&gt;-&lt;/span&gt; Return &lt;span class="sb"&gt;`ResponseEntity&amp;lt;T&amp;gt;`&lt;/span&gt;; route errors through the global
  &lt;span class="sb"&gt;`@RestControllerAdvice`&lt;/span&gt;, never inline try/catch in controllers.
&lt;span class="p"&gt;-&lt;/span&gt; Tests: JUnit 5 + AssertJ; MockMvc for controllers, &lt;span class="sb"&gt;`@DataJpaTest`&lt;/span&gt; for repos.

&lt;span class="gu"&gt;## Commands&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Build and test: &lt;span class="sb"&gt;`./mvnw -q test`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Do NOT run &lt;span class="sb"&gt;`./mvnw clean`&lt;/span&gt; unless I explicitly ask.

&lt;span class="gu"&gt;## Rules&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; After any change, run &lt;span class="sb"&gt;`./mvnw -q test`&lt;/span&gt; and only tell me you are done
  if it passes.
&lt;span class="p"&gt;-&lt;/span&gt; Match the surrounding file style. Do not "modernize" working code to streams.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last rule — &lt;em&gt;only say done if it passes&lt;/em&gt; — is the highest-leverage sentence in the file. Left alone, Codex will hand you a diff it never compiled. One line forces it to find its own compile errors before it talks to you.&lt;/p&gt;

&lt;p&gt;Codex also supports cascading &lt;code&gt;AGENTS.md&lt;/code&gt; files, so in a multi-module build the payments module can carry tighter rules than the shared library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approval modes: why I don't run full-auto on Java
&lt;/h2&gt;

&lt;p&gt;There are three modes: &lt;code&gt;suggest&lt;/code&gt; (propose everything), &lt;code&gt;auto-edit&lt;/code&gt; (edit files, ask before shell), and &lt;code&gt;full-auto&lt;/code&gt; (the whole loop, sandboxed with network off).&lt;/p&gt;

&lt;p&gt;Full-auto feels like the future and is how you lose an afternoon. On a real working copy it will decide &lt;code&gt;target&lt;/code&gt; is stale, run &lt;code&gt;./mvnw clean&lt;/code&gt;, and then sit there unable to reach your internal Nexus mirror to re-download a dependency. It also can't reach your database, so any test expecting a live datasource fails in the sandbox and Codex reports "tests failed" with no useful reason.&lt;/p&gt;

&lt;p&gt;On Java I keep it on &lt;code&gt;suggest&lt;/code&gt;. &lt;code&gt;auto-edit&lt;/code&gt; is the middle ground for refactoring one module where I trust the edits but want to eyeball the commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cloud sandbox is the best and worst part
&lt;/h2&gt;

&lt;p&gt;The sandbox is the headline safety feature and the biggest Spring Boot gotcha at once.&lt;/p&gt;

&lt;p&gt;What bit me: I handed Codex a task whose integration test hit a local Postgres. Green locally. In the sandbox, no Postgres and no network — so the test failed and Codex spent its budget &lt;em&gt;refactoring the test&lt;/em&gt; instead of the feature.&lt;/p&gt;

&lt;p&gt;The rule I landed on: scope Codex tasks to things covered by &lt;code&gt;@DataJpaTest&lt;/code&gt; with an embedded or Testcontainers database, or treat Cloud as a code generator and verify locally yourself. If the task needs your real network or your real database, it is not a Cloud task.&lt;/p&gt;

&lt;h2&gt;
  
  
  A concrete run: "fix this issue and open a PR"
&lt;/h2&gt;

&lt;p&gt;A teammate filed a bug — pagination on &lt;code&gt;GET /api/orders&lt;/code&gt; ignored the sort parameter and silently returned insertion order. I tagged &lt;code&gt;@codex&lt;/code&gt; with a one-line brief: &lt;em&gt;sort by &lt;code&gt;createdAt desc&lt;/code&gt; when no sort param is given, add a test proving it, open a PR.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Fifteen minutes later: a branch, a three-line controller change, a test that genuinely proved the regression, and a PR description.&lt;/p&gt;

&lt;p&gt;What it got wrong: it put the sort inside the controller instead of pushing it into the repository query method — exactly the layering rule my &lt;code&gt;AGENTS.md&lt;/code&gt; forbids. The instruction slowed it down but didn't stop it. I moved it down in about a minute and merged.&lt;/p&gt;

&lt;p&gt;That's the honest shape of the win. It does the bulk of the mechanical work; I own the last five percent and all of the judgment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it still trips up
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The network wall.&lt;/strong&gt; Maven mirrors, databases, internal services — none exist in Cloud. Plan around it or run locally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token-metered billing.&lt;/strong&gt; A Spring Boot build with a long tool-call loop burns credits far faster than flat-rate days did. I watch the dashboard now the way I used to watch my cloud bill.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No persistent local state.&lt;/strong&gt; Each Cloud task starts from a fresh checkout. If the context isn't in &lt;code&gt;AGENTS.md&lt;/code&gt;, you re-explain the terrain every single time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business logic it can't see.&lt;/strong&gt; It will write code that compiles and passes the tests &lt;em&gt;it&lt;/em&gt; wrote, then get the business rule subtly wrong. A green build is not correct behaviour, and that part stays on me.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weaker enforcement than hooks.&lt;/strong&gt; The sandbox is coarse: strong isolation, weak "never touch this specific file" control. Claude Code's hooks still win there.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The setup, in five lines
&lt;/h2&gt;

&lt;p&gt;Install the CLI. Write a tight &lt;code&gt;AGENTS.md&lt;/code&gt; (build command + the "only done if tests pass" rule). Keep approval on &lt;code&gt;suggest&lt;/code&gt; for anything on a real working copy. Verify on your own machine when the task needs a database Cloud can't reach. Review every diff like a stranger wrote it — because a stranger effectively did.&lt;/p&gt;

&lt;p&gt;Do that and Codex becomes a reliable junior pair that ships its own PRs. Skip the discipline and it becomes the fastest way yet to merge something that builds green and behaves wrong.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I write about what AI coding agents actually do to real Spring Boot codebases — including the parts where the build goes green and the feature silently isn't there. The longer version of this one, with the full &lt;code&gt;AGENTS.md&lt;/code&gt; and the failure logs, is at &lt;a href="https://aikitguides.com/blog/codex-spring-boot/" rel="noopener noreferrer"&gt;aikitguides.com/blog/codex-spring-boot&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
