대부분의 'Codex를 Java에 적용해봤다'라는 글들은 새로운 프로젝트(greenfield)로 시작하는 할 일 목록 앱을 사용합니다. 저는 정반대의 방식을 취했습니다. 실제 도메인 모델, MapStruct 매퍼, Flyway 마이그레이션 기록, 그리고 이미 에이전트가 등장하기 전에 존재했던 테스트 스위트를 갖춘 Spring Boot 모노레포(monorepo)를 사용했죠.
저는 몇 주 동안 이것을 실행했습니다. 저를 놀라게 한 것은 그것이 실패한 지점이 아니었습니다. 바로 '완료된 것처럼 보였지만 실제로는 그렇지 않았던' 지점들이었습니다.
Codex와 Claude Code는 다른 형태이다
가장 먼저 이해해야 할 점은 'Codex'라는 이름 아래 두 가지 제품이 있다는 것입니다. 하나는 터미널에서 사용하는 오픈 소스 CLI이고, 다른 하나는 대시보드나 GitHub 이슈에 @codex를 태그하여 트리거하는 비동기 에이전트(async agent)인 Codex Cloud입니다.
Claude Code와의 사고방식 차이가 기능적 격차보다 더 중요합니다. Claude Code는 상호작용적(interactive)입니다. 작동하는 것을 지켜보고, 위험한 단계가 도착할 때마다 승인해 줍니다. 반면, Codex는 위임(delegation)을 위해 구축되었습니다. 작업을 설명하고 자리를 비운 다음, diff나 PR로 돌아옵니다. 저는 세 개의 작은 작업을 예약하고 노트북을 닫은 후 저녁 식사 후에 검토합니다. Claude Code를 돌보듯이 Codex를 돌볼 필요가 없고, 마찬가지로 Claude Code를 그렇게 마음대로 실행할 수도 없습니다. 이 분리가 제가 두 가지 모두 설치해 놓는 이유입니다.
비용 대비 효과가 큰 AGENTS.md의 한 줄
AGENTS.md는 Codex의 프로젝트 지침 파일이며, 이는 Claude Code의 CLAUDE.md와 쌍을 이룹니다. Codex는 첫 실행 시 이를 작성하도록 제안합니다. 그렇게 하도록 두고, 그 내용 중 절반은 버리세요. 마치 /init처럼요. 생성된 지침 파일들은 알 수 없는 관습들을 추측할 뿐입니다.
실제로 제가 Spring Boot / Java 21 / Maven 앱에서 실행하는 내용은 다음과 같습니다:
## Project
- Spring Boot, Java 21, Maven. Wrapper 사용: `./mvnw`.
- 계층 구조(Layering): controller -> service -> repository. 컨트롤러에는 비즈니스 로직을 넣지 않는다.
...
마지막 규칙 — 통과했을 때만 완료라고 말하라 — 가 이 파일에서 가장 높은 레버리지(high-leverage)를 가진 문장입니다. 아무런 제약이 없다면, Codex는 컴파일되지 않은 diff를 제시할 것입니다. 이 한 줄은 그것이 사용자에게 말을 걸기 전에 스스로 컴파일 오류를 찾도록 강제합니다.
Codex는 또한 캐스케이딩(cascading) AGENTS.md 파일을 지원하므로, 다중 모듈 빌드 환경에서 결제(payments) 모듈이 공유 라이브러리보다 더 엄격한 규칙을 가질 수 있습니다.
승인 모드: 왜 Java에서 전체 자동(full-auto)을 실행하지 않는가
세 가지 모드가 있습니다: suggest(모든 것을 제안), auto-edit(파일 편집 후 셸 실행 전 질문), 그리고 full-auto(전체 루프, 네트워크가 차단된(sandboxed) 환경).
Full-auto는 미래처럼 느껴지지만 오후 시간을 낭비하게 만드는 방식입니다. 실제 작업 복사본(working copy)에서는 target이 오래되었다고 판단하고 ./mvnw clean을 실행한 다음, 내부 Nexus 미러에 접속하여 종속성(dependency)을 다시 다운로드할 수 없어 그저 멈춰 있게 됩니다. 또한 데이터베이스에도 접근할 수 없기 때문에, 라이브 데이터 소스(live datasource)를 예상하는 모든 테스트가 샌드박스에서 실패하고 Codex는 유용한 이유 없이 "테스트 실패(tests failed)"라고 보고합니다.
저는 Java에서는 suggest를 유지합니다. auto-edit은 제가 편집 내용을 신뢰하지만 명령어를 눈으로 확인하고 싶은 모듈을 리팩터링(refactoring)할 때의 중간 단계입니다.
클라우드 샌드박스는 가장 좋고도 최악인 부분
샌드박스는 동시에 가장 주목받는 안전 기능이자, 가장 큰 Spring Boot의 함정(gotcha)입니다.
저를 당황하게 한 것: 저는 Codex에게 로컬 Postgres에 연결되는 통합 테스트(integration test)가 포함된 작업을 맡겼습니다. 로컬에서는 성공했습니다. 하지만 샌드박스에는 Postgres도, 네트워크도 없었기 때문에 테스트가 실패했고, Codex는 기능(feature)을 리팩터링하는 대신 _테스트를 리팩터링_하는 데 예산을 사용했습니다.
제가 정한 규칙: Codex 작업을 임베디드(embedded) 또는 Testcontainers 데이터베이스로 커버되는 @DataJpaTest와 같은 것에 한정하거나, 클라우드를 코드 생성기(code generator)로 취급하고 직접 로컬에서 검증해야 합니다. 만약 작업이 실제 네트워크나 실제 데이터베이스를 필요로 한다면, 그것은 클라우드 작업이 아닙니다.
구체적인 실행 사례: "이 문제를 수정하고 PR을 열어줘"
팀원이 버그를 보고했습니다 — GET /api/orders의 페이지네이션이 정렬 매개변수(sort parameter)를 무시하고 삽입 순서로 조용히 반환하는 문제였습니다. 저는 @codex에 한 줄 요약으로 태그를 달았습니다: 정렬 매개변수가 주어지지 않으면 createdAt desc로 정렬하고, 이를 증명하는 테스트를 추가하며, PR을 열어줘.
15분 후: 브랜치 하나, 세 줄짜리 컨트롤러 변경 사항, 실제로 회귀(regression)를 증명하는 테스트, 그리고 PR 설명서가 완성되었습니다.
잘못한 점: 정렬(sort) 로직을 리포지토리 쿼리 메서드에 넣는 대신 컨트롤러 안에 두었습니다. 이는 제가 AGENTS.md에서 금지하는 계층화 규칙과 정확히 모순됩니다. 이 지침 때문에 속도가 느려졌지만, 완전히 막지는 못했습니다. 저는 약 1분 만에 그것을 아래로 옮기고 병합했습니다.
이것이 승리의 솔직한 모습입니다. 대부분의 기계적인 작업은 얘가 처리하고, 마지막 5퍼센트와 모든 판단은 제가 담당합니다.
여전히 문제가 되는 부분
- 네트워크 장벽. Maven 미러(mirrors), 데이터베이스, 내부 서비스 등은 클라우드 환경에는 존재하지 않습니다. 이를 염두에 두고 계획을 세우거나 로컬에서 실행해야 합니다.
- 토큰 기반 청구(Token-metered billing). 긴 도구 호출 루프를 가진 Spring Boot 빌드는 종량제 일일 요금보다 크레딧을 훨씬 빠르게 소모합니다. 저는 이제 예전처럼 클라우드 청구서를 보듯이 대시보드를 확인합니다.
- 지속적인 로컬 상태 부재. 각 클라우드 작업은 새로운 체크아웃(checkout)부터 시작합니다. 만약 컨텍스트가
AGENTS.md에 없다면, 매번 지형을 재설명해야 합니다.
- 볼 수 없는 비즈니스 로직. 컴파일되고 얘가 작성한 테스트를 통과하는 코드를 작성하지만, 비즈니스 규칙은 미묘하게 틀릴 수 있습니다. 녹색 빌드(green build)가 올바른 동작을 의미하지 않으며, 이 부분은 제가 책임져야 합니다.
- 훅(hooks)보다 약한 강제성. 샌드박스는 거칩니다: 강력한 격리성은 갖추었지만,
저는 AI 코딩 에이전트가 실제 Spring Boot 코드베이스에서 무엇을 하는지에 대해 글을 씁니다. 빌드가 성공적으로 완료되는 부분부터 기능이 조용히 빠져 있는 경우까지 포함해서요. 전체 AGENTS.md와 실패 로그를 담은 더 긴 버전의 글은 aikitguides.com/blog/codex-spring-boot에서 확인하실 수 있습니다.