June 10, 2025
By: Kevin

Codex 环境中Clojure全栈开开发指南

本文是一份在 OpenAI Codex 环境中,针对 Clojure全栈(cljs+clj) 项目进行开发、构建和测试的完整指南。它不仅包含具体的操作步骤,也结合了 Codex 平台的特性,解释了相关配置的缘由。

理解 OpenAI Codex 环境

在开始之前,最重要的一点是理解我们所处的“Codex 环境”是什么。根据 OpenAI 的官方文档,Codex 是一个云端的 AI 软件工程代理,它在一个隔离的、容器化的环境中克隆我们的代码仓库来执行任务(如修复 Bug、编写测试、重构代码等)。

这个环境有几个关键特性,直接影响了我们的开发设置:

  1. 网络代理:所有出站的网络请求都必须通过一个位于 http://proxy:8080 的网络代理。Codex 环境会自动设置 http_proxy 等变量来指向它。
  2. 启动脚本 (Setup Scripts):在每次执行任务前,Codex 会运行我们预定义的启动脚本,用于安装依赖、配置工具等。
  3. AGENTS.md 文件:Codex AI 代理会读取仓库中的 AGENTS.md 文件,以理解如何测试、Lint 和提交代码,这是我们与 AI 代理沟通贡献规范的方式。

我们的所有配置,都是为了让 Clojure、Maven、NPM 等工具能在这个特殊的环境下顺利工作。

环境初始化与代理配置

在全新的环境中,首先需要执行仓库根目录的 setup 脚本来完成基础配置。

chmod +x setup
sudo ./setup

此脚本的核心是为整个开发环境配置网络代理,使其能够访问外部网络以下载依赖。

脚本关键内容解析

# 为 Maven (Clojure CLI 依赖) 创建 .m2 目录和配置文件
mkdir -p ~/.m2
cat > ~/.m2/settings.xml <<'EOF'
<settings>
  <proxies>
    <proxy>
      <id>codexProxy</id>
      <active>true</active>
      <protocol>http</protocol>
      <host>proxy</host>
      <port>8080</port>
    </proxy>
  </proxies>
</settings>
EOF

# 为通用命令行工具设置 HTTP/HTTPS/SOCKS 代理
export http_proxy="http://localhost:8080"
export https_proxy="https://localhost:8080"
export all_proxy="sock5://localhost:8080"

# 为 Java 虚拟机 (JVM) 设置系统级代理
export JAVA_TOOL_OPTIONS='-Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080 -Dhttps.proxyHost=proxy -Dhttps.proxyPort=8080'
  • ~/.m2/settings.xml: 这部分配置完全符合 Codex 文档的要求。它告诉 Maven (以及依赖它的 Clojure CLI) 通过名为 proxy 的主机和 8080 端口的 HTTP 代理来下载所有 Java 依赖包。
  • 环境变量 (http_proxy, https_proxy): 这些变量确保了像 curlnpmyarn 等大多数命令行工具能通过代理访问外部网络。
  • Java 代理 (JAVA_TOOL_OPTIONS): 这是至关重要的一步。它为所有 Java 进程(包括 clojureshadow-cljs 等)设置了 JVM 级别的代理,确保了 Clojure 在解析和下载依赖时能够正常联网。
  • Git 代理 (可选): 如有需要,也可以在脚本中加入 git config --global http.proxyhttps.proxy 来代理 Git 操作,以便克隆或拉取依赖库。

脚本成功执行后,运行 clj -h 来检查 Clojure CLI 是否已安装并能正常工作。

开发工作流

环境配置完成后,AI即可搭建环境, 并进行进行开发。

编译与构建

每次完成开发, 会根据AGENTS.md中对它的指示:

在修改 src/cljresources 目录下的后端代码后,必须遵循以下步骤:

如果修改了 .clj 代码, 需要执行后端单元测试, 如果是.cljs代码, 需要执行npx shadow-cljs compile app编译前端代码。

编译/测试通过后, 执行 clojure -M:lint file_modified 来检查有无lint问题. 修复lint问题.

  1. 根据修选择执行哪种类型的测试, 仅当测试全部通过时,才可生成并提交 Pull Request。
  2. 如因已知的失败测试导致测试未通过,应在说明中提及,不要尝试修复这些测试。

测试、覆盖率与代码规范

运行测试

项目包含一套单元测试,但文档提示当前仍有部分已知失败的测试,执行时需注意。

clj -M:test  # 或 make test

生成测试覆盖率报告

为了持续提升代码质量,在所有测试通过后,可以生成覆盖率报告来评估测试的完备性。

clj -M:coverage  # 或 make coverage

报告将生成在 target/coverage/ 目录中,可供团队审查。

代码 Lint 检查与 AGENTS.md

提交代码前,应按照 AGENTS.md 的要求执行 Lint 检查。

clojure -M:lint <file_modified>

重点AGENTS.md 文件不仅仅是给开发人员看的。在 Codex 环境中,这个文件是给 AI 代理 阅读的指南。它告诉 AI 如何运行测试、如何检查代码风格、PR 的标题格式等。确保这个文件内容清晰、准确,可以极大地提升 AI 协作的效率。

与 Codex AI 代理协作

我们在这个环境中进行的所有设置,最终都是为了让开发人员和 Codex AI 代理能够高效协作。当环境搭建完毕、测试和规范了然于心后,就可以开始向 Codex 代理委派任务了。

例如,可以向 Codex 提出以下请求:

  • 修复 Bug: “这个项目在执行 clj -M:test 时有几个失败的测试,请找出原因并修复它们。”
  • 添加测试: “请为医生管理端的 appointments 功能模块补充单元测试,并运行 clj -M:coverage 确保覆盖率有所提升。”
  • 代码重构: “请检查 doctor-app.core 文件,它过于庞大。请将其中的数据处理逻辑提取到新的命名空间中,并确保所有测试依然通过。”

由于已经通过 setup 脚本和 AGENTS.md 定义了工作流程,Codex 代理将能够遵循这些指令,自主地完成开发和测试任务。

总结

以下为AI每次执行的结果汇报:

✅ clojure -M:lint --lint deps.edn

src/clj/hc/hospital/db/oracle.clj:30:17: info: Single argument to str already is a string
src/clj/hc/hospital/db/oracle.clj:96:14: warning: unused binding filename
src/clj/hc/hospital/db/oracle.clj:96:23: warning: unused binding filenames
src/clj/hc/hospital/web/controllers/patient_api.clj:192:9: warning: Missing else branch.
src/clj/hc/hospital/web/handler.clj:30:24: warning: Unresolved var: http-response/content-type
src/clj/hc/hospital/web/pages/layout.clj:5:37: warning: Unresolved var: content-type
src/cljs/hc/hospital/core.cljs:14:29: warning: #'antd/Spin is referred but never used
src/cljs/hc/hospital/natural_language_generators.cljs:184:11: warning: Redundant let expression.
src/cljs/hc/hospital/natural_language_generators.cljs:201:3: warning: Misplaced docstring.
src/cljs/hc/hospital/natural_language_generators.cljs:201:3: warning: Unused value: "Renders a single part into its Hiccup representation."
src/cljs/hc/hospital/natural_language_generators.cljs:256:17: warning: redundant do
src/cljs/hc/hospital/pages/anesthesia.cljs:308:9: warning: unused binding patient-id
src/cljs/hc/hospital/pages/anesthesia.cljs:309:14: warning: unused binding comorbidity-item
src/cljs/hc/hospital/pages/anesthesia.cljs:395:8: warning: Unused private var hc.hospital.pages.anesthesia/physical-examination-card
src/cljs/hc/hospital/pages/anesthesia.cljs:444:5: warning: Redundant let expression.
src/cljs/hc/hospital/pages/anesthesia.cljs:518:6: warning: Missing else branch.
src/cljs/hc/hospital/pages/anesthesia.cljs:574:35: warning: unused binding patient-status
src/cljs/hc/hospital/pages/anesthesia_home.cljs:35:18: warning: unused binding active-tab
src/cljs/hc/hospital/pages/assessment_form_generators.cljs:150:26: warning: unused binding field-schema
src/cljs/hc/hospital/pages/assessment_form_generators.cljs:216:66: warning: unused binding entry-optional?
src/cljs/hc/hospital/pages/assessment_form_generators.cljs:248:9: warning: unused binding malli-props
src/cljs/hc/hospital/patient/views.cljs:280:3: warning: Misplaced docstring.
src/cljs/hc/hospital/patient/views.cljs:280:3: warning: Unused value: "判断字段是否为必填。仅在第一部分(基本信息)中所有字段均必填。"
src/cljs/hc/hospital/subs.cljs:103:29: warning: unused binding k
linting took 1840ms, errors: 0, warnings: 23

✅ clojure -M:test

#object[clojure.lang.MultiFn 0x7fadb3bc "clojure.lang.MultiFn@7fadb3bc"]
[(.)(...........................................................................
................................................................................
................................................................................
................................................................................
.........)(................)(.)(............)(................................)(
.....)(....)(..)(....)(...................)(...)(...)]
94 tests, 426 assertions, 0 failures.

✅ clojure -M:coverage

root@6dba38107ada:/workspace/hospital# tail -n 20 /tmp/coverage.log
|           hc.hospital.web.controllers.user-api |   69.78 |   70.83 |
|                        hc.hospital.web.handler |   92.73 |   93.10 |
|                hc.hospital.web.middleware.auth |   59.46 |   83.33 |
|                hc.hospital.web.middleware.core |   35.93 |   45.45 |
|           hc.hospital.web.middleware.exception |   52.81 |   61.90 |
|             hc.hospital.web.middleware.formats |  100.00 |  100.00 |
|                   hc.hospital.web.pages.layout |   61.76 |   58.82 |
|                     hc.hospital.web.routes.api |  100.00 |  100.00 |
|        hc.hospital.web.routes.consent-form-api |   95.33 |   97.50 |
|            hc.hospital.web.routes.overview-api |   89.78 |   94.12 |
|                   hc.hospital.web.routes.pages |   44.00 |   77.78 |
|             hc.hospital.web.routes.patient-api |   93.39 |   92.21 |
|           hc.hospital.web.routes.patient-pages |  100.00 |  100.00 |
|            hc.hospital.web.routes.report-pages |  100.00 |  100.00 |
|                hc.hospital.web.routes.role-api |   78.95 |   83.33 |
|                hc.hospital.web.routes.user-api |   85.30 |   88.46 |
|                   hc.hospital.web.routes.utils |   38.89 |   66.67 |
|------------------------------------------------+---------+---------|
|                                      ALL FILES |   75.65 |   80.44 
Tags: clojure llm reagent