我最近把新项目从零开始配置 AI 编程环境的流程,整成了一键脚本。所谓“配置 AI 编程环境”,说的是这么三件事:装好 Codex 这个终端里的 AI 结对程序员,铺好 OpenSpec 的规格驱动目录,再把 Matt Pocock 那套 skills 塞进项目,让 AI 打开仓库就知道按什么方法论干活、处理 TypeScript 时用哪些最佳实践。以前这套流程我每周至少手动执行两三遍,每次都要翻旧项目的配置去复制粘贴,还会漏东西。上个月我实在忍不了了,花了几个晚上把它写成脚本,现在任何新项目,跑一条命令就能开工。
这篇文章把我踩过的坑、脚本的设计思路、关键步骤的代码片段、还有实际运行中遇到的一堆报错都整理出来。如果你也是用 Codex、Claude Code 这类终端 AI 工具做全栈开发的人,看完可以直接抄作业,把这套初始化脚本搬到你自己或团队的项目脚手架里。
1. 项目初始化流程到底卡在哪
1.1 没有初始化流程时的“手动地狱”
先说没做脚本之前,我每次开一个新项目的标准流程,你感受一下有多烦。
先要在终端里确认 Codex 装没装、登录没登录,然后手动创建 AGENTS.md,把项目技术栈、目录约定、代码风格要求一条条写进去。写完 AGENTS.md,还得初始化 OpenSpec 的规格目录,手动建spec/requirements这些文件夹,再从旧项目里翻出需求模板拷过来。接着去 GitHub 上找 Matt Pocock 的 skills 仓库,克隆到当前项目,再回到 AGENTS.md 里写上“skills 在哪个目录、什么时候该用哪些技能”。最后还要打开 Codex,跑一个随机任务测试环境到底通不通。
这套流程我跑过很多遍,每次最少 20 分钟,慢的时候能磨蹭到一个小时。更难受的是,它完全依赖记忆。有一回我急着开工,忘了在 AGENTS.md 里写清楚目录约定,结果 Codex 自己在根目录下面建了一堆utils/、helpers/、services/,把项目结构搞得一团糟;还有一次忘了装 skills,AI 生成的 TypeScript 组件从条件类型到泛型约束全是反面教材。
后来我想明白一件事:这些初始化步骤里没有一步是“需要人现场动脑子决定”的,全是机械的、固定的、可重复的操作。既然是机械操作,就理应交给脚本,让机器去跑,我负责最后验收。
1.2 Codex、OpenSpec、Skills 各自扮演什么角色
这三样东西很多人单独用过,但未必清楚它们放在一起时是怎么分工的。我按自己的理解给它们排了个序:
| 工具 | 角色 | 解决什么问题 |
|---|---|---|
| Codex | 执行者 | 把自然语言任务变成代码改动,在终端里跑命令、改文件、做验证 |
| OpenSpec | 需求翻译器 | 把模糊的“我要做个 XX 功能”转成结构化、可验收的规格文档 |
| Matt Pocock Skills | 方法论包 | 给 AI 预装“怎么写出高质量 TypeScript/React 代码”的经验库 |
Codex 是干活的人,OpenSpec 是让干活的人先想清楚再动手的流程约束,skills 是干活时调用的一身本领。单独用 Codex,AI 就像一个能力强但容易飘的实习生,你说什么它做什么,但没人管需求边界,也没人教它你们团队的最佳实践;加上 OpenSpec,AI 会先读规格再动手,而不是上来就写代码;再加上 skills,AI 处理 Vue、React、TypeScript 泛型这些事情时,会主动套用经过验证的写法,而不是自由发挥。
1.3 为什么值得把整套流程“一键化”
有人可能会说,手动配一次也不慢,至于写脚本吗?我的回答是:一次两次确实不至于,但这件事不是一次性投入。
第一,我在多个项目之间来回切,新项目开得频繁,不开新项目也要给旧项目补环境。第二,团队协作时每个人手动配置,配出来的环境几乎必然有差异——你用的是旧版 skills,他 clone 的是最新 commit,她干脆忘了配 OpenSpec,最后 AI 在所有人机器上行为不一致,排查起来头大。第三,脚本本身就是文档。你把初始化逻辑写进脚本,等于把“正确姿势”固化成了可执行代码,比写十页 wiki 都可靠。
写脚本那几天我也犹豫过,觉得是不是过度工程了。但跑通一次之后我就确信:这个投入非常值。现在的体感就像以前每次新租房子都要自己拉网线、装路由器、调电视,现在物业直接把所有东西都配好,你进门扫码就能用。
2. 一键脚本的整体设计思路
2.1 先定边界:脚本负责什么,不负责什么
动手写脚本前,我做的第一件事不是写代码,而是列需求和边界。因为初始化脚本这类东西最容易膨胀——你想让它顺便装依赖、初始化 git、生成 README、配 ESLint、装 husky……最后变成一个大泥球。
我给脚本定的目标是:把“AI 编程环境”从零配好,让 Codex 打开这个仓库就能按预期方式工作。具体来说它负责四件事:环境检测与依赖安装、生成 Codex 侧配置文件、初始化 OpenSpec 规格目录、安装 skills 并验证连通性。
它明确不负责的事也很多:不帮你写业务代码、不初始化 git 远端、不装业务依赖、不管 CI/CD 配置。这些内容每个项目差异太大,塞进初始化脚本只会让脚本变得难以维护。我的原则是:凡是“因项目而异”的部分,脚本一概不管;凡是“所有 AI 驱动项目都通用”的部分,脚本全部覆盖。
2.2 目标目录结构设计
脚本的核心产出是目录结构和配置文件。我设计的标准模板长这样:
my-new-project/ ├── AGENTS.md # Codex / Claude Code 都会读取的项目级指令 ├── .gitignore ├── .codex/ │ ├── config.toml # Codex 运行时配置(模型、模式、技能路径) │ └── skills/ # 项目级 skills 挂载点 ├── spec/ │ ├── README.md # 规格目录说明 │ ├── requirements/ # 需求规格存放处 │ └── tasks/ # 拆解后的任务清单 ├── skills/ # Matt Pocock Skills 克隆到这里 │ ├── SKILL.md │ └── typescript/ # 各类专业技能子目录 ├── src/ │ └── index.ts # 最小可运行入口 ├── package.json ├── tsconfig.json └── README.md关键设计决策有两个。第一,skills/和.codex/skills/分开放:前者是 skills 仓库的原始克隆,后者是 Codex 实际扫描的目录,里面可以放软链或选择性拷贝,避免把庞大的技能库原封不动暴露给 Codex,也方便以后换别的 skill 源。第二,AGENTS.md放在仓库根目录,因为这个文件不仅要给 Codex 看,Claude Code 和其他 AI 工具也认它,这是一个目前生态里的通用约定。
2.3 脚本主流程:五段式
脚本整体走五段式流程,每段结束都输出明确的状态信息,出错立即停止,不会带着坏环境继续往下跑。
- 检查环境:确认 node、git、npm/pnpm 是否安装,检查 Codex 是否可用,缺失则自动安装。
- 生成骨架:创建目录结构、package.json、tsconfig(如指定)、src 入口。
- 写入配置:生成 AGENTS.md、.codex/config.toml、填充 OpenSpec 模板。
- 安装技能:克隆或更新 Matt Pocock skills,建立软链到 .codex/skills。
- 自动验收:用
codex exec跑一个只读的连通性任务,确认 AI 能正确读取指令和技能目录。
为什么按这个顺序?因为每一段都依赖前一段的产物。环境不检查就往下走,装到一半发现 npm 没装,全白搭;不先生成骨架,AGENTS.md 里没法写实际的目录结构;不装 skills,最后的验收任务也测不到真正的完整链路。顺序搞对了,任何一步报错都能快速定位。
3. 核心实现:脚本逐步拆解
3.1 环境检测与依赖准备
脚本第一部分是环境检测,核心逻辑用三个函数搞定。我贴一下关键代码片段。
check_command() { if command -v "$1" &> /dev/null; then echo "[OK] $1 已安装: $(command -v "$1")" return 0 else echo "[WARN] $1 未找到" return 1 fi } ensure_codex() { if check_command "codex"; then codex --version else echo "未检测到 codex,尝试通过 npm 全局安装..." npm install -g @openai/codex fi }这里有一个容易踩的坑:command -v只能检测命令是否存在,检测不了命令是否真的能用。我遇到过 npm 全局目录里 codex 装了一半、二进制文件残缺的情况,command -v返回正常,但一执行就报错。所以我在检测之后还会加一个实际的版本探测,拿返回值判断,而不是看到文件存在就放行。
另外,安装 Codex 时权限问题非常常见。npm install -g如果报 EACCES,多半是 npm 全局目录权限不对。我建议优先用 nvm 管理 Node 环境,全局包装在用户目录下,比用 sudo 硬解干净得多。脚本里不会替你 sudo,遇到权限问题就直接报错退出,提示你先解决全局包写入权限。
3.2 生成 Codex 侧配置:AGENTS.md 与 config.toml
AGENTS.md 是整个项目 AI 协作的“宪法”。它不需要很长,但必须把最关键的信息写清楚:项目简介、技术栈、目录结构约定、AI 的工作模式、禁止事项、skills 的使用说明。
我模板里必写的几段内容如下。
# 项目指令 ## 项目概述 (这里填项目一句话简介) ## 技术栈 - TypeScript + Node.js(具体按参数生成) ## 目录约定 - src/:业务源码 - spec/:需求与任务规格,改动功能前先读对应规格 - skills/:可复用的 AI 技能包,按任务类型查阅 ## AI 工作模式 - 修改代码前先检查 AGENTS.md 和 spec/ 对应文档 - 任务拆解按 spec/tasks 下的清单推进 - 涉及 TypeScript 类型设计时,优先查阅 skills/typescript 下的最佳实践 ## 禁止事项 - 不要在根目录随意创建新目录,新模块需先定义到 spec/ 中 - 不要一次性大范围重构,除非任务规格中明确要求生成 config.toml 时,我倾向于只用最少的配置,因为 Codex 的很多默认行为已经够用。重点是模型选择、技能目录挂载和审批模式。简单版本大概长这样:
[model] # 我用 ChatGPT 账号登录时,模型取决于账号可用集合 # 用 API key 认证时,这里可以显式指定支持你项目需求的模型 # 不确定时留空,让 Codex 走默认 [approval] # 自动模式只读命令免审批,写操作需要确认 # 脚本里验收任务跑的是只读命令,开发时建议保守一点这段配置我不写死模型名,因为不同认证方式下可用模型差异太大,写了反而容易踩“模型不支持”的坑。
3.3 OpenSpec 初始化:把“想法”变成“可验收的规格”
OpenSpec 的价值在于强迫 AI 先理解需求再动手。脚本初始化它的方式很简单:创建目录骨架,写入说明文档和需求模板。
mkdir -p spec/requirements spec/tasks cp templates/spec-requirements.md spec/requirements/_template.md cat > spec/README.md <<'EOF' # 规格目录说明 本目录使用 OpenSpec 工作流: 1. 新需求先写 requirements/ 下的规格文档 2. 用 "需求背景 -> 行为变更 -> 验收标准" 三段式描述 3. 拆解为任务后放入 tasks/,逐步推进 EOF这里有个细节值得说:模板文件我用的是“三段式”,因为这是 OpenSpec 工作流的核心思想。需求背景解释为什么要做;行为变更描述 AI 做完之后系统会有什么不同;验收标准列几条可执行、可判断真假的检查点。这个格式逼着你在写需求时就把“什么叫做完”定义清楚,而不是丢一句“做个登录页”就完事。
实测下来,同样一个“实现用户登录”的需求,直接丢给 Codex 和按 OpenSpec 三段式写好规格再让 Codex 干,后者的交付质量明显稳定,尤其是改动范围大、涉及多个文件的功能。
3.4 安装 Matt Pocock Skills:克隆、锁定、挂载
Skills 的安装是脚本核心环节之一。直接 clone 一个仓库到项目里是不够的,还要处理版本锁定和挂载路径。
skills_repo="https://github.com/mattpocock/你的-skills-仓库地址.git" skills_ref="2025.11.01" # 建议锁定到稳定 commit 或 tag if [ -d "skills/.git" ]; then git -C skills fetch --depth 1 origin "$skills_ref" git -C skills checkout "$skills_ref" else git clone --depth 1 --branch "$skills_ref" "$skills_repo" skills fi ln -sfn "../skills" .codex/skills为什么特意加--depth 1和锁定版本?因为 skills 仓库迭代频率很高,今天 clone 的最新版可能明天就有了破坏性变更。锁定版本之后,同一个项目在任何机器上初始化,拿到的 skills 内容完全一致,团队协作时不会出现“大家用的方法论不一样”的诡异情况。
软链挂载到.codex/skills的做法,是我试了几种方式后保留下来的。最开始我直接复制,但 skills 仓库一更新就要重新拷贝,麻烦;后来用 git submodule,但需要团队都会用 submodule,学习成本高;最终用了简单的文件夹软链,既能让 Codex 扫描到技能目录,又方便随时更新。
3.5 结尾验收:让 Codex 自己确认环境“能干活”
初始化脚本最后一步是自动验收。我通常会跑一个低风险任务,验证整条链路是通的:
codex exec --full-auto "阅读项目根目录的 AGENTS.md 和 skills 目录,用一句话说明这个项目的技术栈和 AI 工作方式,然后指出配置中的不足之处。不要修改任何文件。"这段任务有三个用处。第一,验证 Codex 能正常启动、认证有效;第二,验证它能读到 AGENTS.md 和 skills 目录;第三,得到一个项目环境的人工可读摘要,方便我肉眼判断有没有配错。如果这一步通过了,脚本才算真正跑完,后续开发就是水到渠成的事。
4. 实际运行效果与参数选型
4.1 脚本参数设计:怎么从一个“通用初始化器”变成“贴身脚手架”
通用脚本能跑,但每个项目还是会有差异。我加了一套命令行参数,让脚本在不同场景下保持灵活,又不用维护多份脚本。
| 参数 | 作用 | 示例 |
|---|---|---|
-n, --name | 指定项目目录名 | init-ai-dev -n blog-api |
-t, --typescript | 生成 tsconfig 与 src/index.ts | init-ai-dev --typescript |
--pm | 指定包管理器(npm/pnpm/yarn) | init-ai-dev --pm pnpm |
--no-skills | 跳过 skills 安装,只配 Codex 和 OpenSpec | init-ai-dev --no-skills |
--spec-only | 只初始化 OpenSpec 规格目录 | init-ai-dev --spec-only |
-f, --force | 覆盖已存在的配置文件,否则直接报错 | init-ai-dev -f |
这些参数不是拍脑袋加的,每一个都用实际场景反推过。--no-skills是我在给一个纯 Python 项目初始化时想到的,那项目完全用不到 TypeScript skills;--spec-only是给已经跑着的旧项目补规格用的,不想把别的配置动一遍;--force纯粹是给自己留后路,跑脚本跑出个 bug 需要重来时,不用先删整个项目。
参数解析我用的标准 bash getopts,没有引入额外依赖。复杂是复杂了点,但胜在随处可跑。
4.2 日志输出:每一段都聪明地给出“叫什么、在干嘛、出没出错”
日志设计被很多人忽略,但脚本越复杂,日志越重要。我的脚本每个阶段都有三种状态输出。
[1/5] 检查环境... [OK] node 已安装: v20.11.0 [OK] git 已安装: 2.43.0 [WARN] codex 未找到,执行安装... [OK] codex 已安装: version 1.x.x [2/5] 生成项目骨架... [OK] 创建目录: src, spec/requirements, spec/tasks [OK] 写入 package.json这里我踩过一个坑:最开始日志只输出[OK]和[FAIL],没有阶段编号,结果运行时报错,日志里只有一行[FAIL] mkdir: 权限不足,但根本不知道是脚本第几步出的错。后来我把所有日志改成带阶段前缀的格式,[1/5]、[2/5],报错时一眼就能定位是哪一段的问题。
4.3 手动配置与一键脚本的直观对比
我特意找了一次机会,把同一个新项目开两个文件夹,一个手动配,一个跑脚本,测了一遍真实耗时。
| 场景 | 耗时 | 出错的概率 | 最后得到的配置一致性 |
|---|---|---|---|
| 手动配置 | 17~35 分钟 | 高,容易漏 AGENTS.md 或 skills | 每次都不一样 |
| 一键脚本 | 约 3 分钟(含 npm 安装 Codex) | 低,错误多在环境前置条件 | 完全一致 |
效率提升是最明显的,但对我来说,最大的价值其实是“确定性”。手动配置时内心总有一种不确定感——我是不是漏了什么?这个版本对吗?脚本跑完之后我可以肯定地告诉自己:环境就是这个状态,所有文件都是按标准生成的。对要长期维护一个项目的人来说,这种确定性比那 20 分钟珍贵得多。
5. 常见问题与排查技巧实录
5.1 Codex 连接报错:endpoint 与自定义网关冲突
脚本自动验收阶段,我遇到过一条非常典型的报错:
cc switch local proxy failed while handling codex endpoint /responses第一次看到这个报错时,我还以为是脚本写错了,后来排查半天才发现,问题出在终端环境里配置的自定义 endpoint 网关上。Codex 在处理/responses接口时,会读取当前环境的 endpoint 指向,如果那个指向失效,就会直接报这个错,和脚本本身没有任何关系。
遇到这个报错的排查思路很简单:先确认当前环境有没有额外配置过模型网关或 endpoint,如果有自定义网关指向,先确认服务可用;再查看~/.codex/config.toml中是否残留旧的配置。我在脚本里加了环境预检,如果扫描到非默认 endpoint 配置,就给出警告,避免开发者在错误环境变量下跑初始化还一头雾水。
5.2 “模型不支持”的报错:ChatGPT 账号与自定义模型名冲突
另一个高频报错长这样:
The 'gpt-5.6-sol' model is not supported when using codex with a chatgpt account这个报错本质上是在说:你用 ChatGPT 账号登录 Codex,但 config.toml 里写了一个该账号不支持的自定义模型名。Codex 的模型可用性跟认证方式强相关,同一个模型名,用 API key 认证时可能可用,用 ChatGPT 账号登录时就不一定。
解决方式也简单:要么把 config.toml 里的模型名改成当前认证方式下支持的模型,要么切换认证方式。我的脚本处理方式是,配置文件里默认不写死具体模型,把模型选择权留给用户。这样既不会一安装就报错,也避免逼迫用户去理解 API key 和 ChatGPT 账号的模型差异。
5.3 OpenSpec 目录冲突与重复执行
脚本不是每次都在新目录里跑,有时旧目录里已经有spec/目录了,里面的内容还是项目重要的历史需求文档。最开始我的脚本用mkdir -p只创建缺失的目录,不会主动覆盖,但当需要更新模板时,重复执行会报“目录已存在”之类的问题。
后来我定了这么个规则:所有生成操作都具备幂等性,能覆盖的覆盖,不能覆盖的跳过,绝不删除用户已有内容。加了--force参数后,用户明确说“我要重新初始化”,脚本才会用模板覆盖现有配置文件。开发时这个设计帮我挡住了好几次“手滑覆盖掉重要文档”的灾难。
5.4 Skills 安装了但 Codex 不认
这是最后一个高频问题:按脚本装好了 skills,目录结构完全正确,但 Codex 聊天时完全不提 skills 的存在。我排查下来,九成情况是同一个原因:AGENTS.md 里没有明确说“存有 skills,遇到什么任务应该去读哪个技能”。
Codex 不会自动扫描 project 下的所有目录。它更依赖 AGENTS.md 告诉它项目里有哪些关键文件路径。所以脚本生成的 AGENTS.md 里,必须写清楚“skills 目录在skills/,TypeScript 开发时查看skills/typescript/SKILL.md”,Codex 才知道干活前先去翻技能库。
6. 一点心得体会
脚本跑通之后,我的开发习惯发生了挺大变化。以前开新项目,第一反应是“又要配一堆东西”,多少有点拖延;现在直接一条命令,然后喝口水,回来项目环境已经能用了。这种从“准备环境”到“直接开工”的转变,体验上的提升是质变级的。
我更想说的是,这类初始化脚本的收益会随着使用次数不断放大。每多一次在脚本里修 bug、加参数,都是在给未来的所有项目做一次环境加固。我现在已经把这套脚本收到自己的脚手架仓库里,团队里其他同事要开新项目,我也会直接让他们用这个脚本跑一遍,大家在同一个标准上工作,整个团队的 AI 交付质量都更稳定。
如果以后有空,我还想把它扩展成团队级的初始化命令,把 lint 规范、提交信息规则、甚至容器化配置都统一进去。毕竟 AI 时代的生产力,不能靠每个人各配一套环境来拼,必须靠“可复现的、标准化的启动方式”来托底。