@@ -160,20 +160,14 @@ function validatePrerequisites(opts: CodegenOptions): void {
160160 ) ;
161161 }
162162
163- // Check Python + pydantic are available. Not fatal — the Codex agent has
164- // full access and can install pydantic itself during the run.
163+ // uv must be available (used to manage the workspace venv).
165164 try {
166- const version = execSync (
167- 'python3 -c "import pydantic; print(pydantic.VERSION)"' ,
168- { encoding : "utf8" , stdio : [ "pipe" , "pipe" , "pipe" ] } ,
169- ) . trim ( ) ;
170- log ( opts , `Found pydantic ${ version } ` ) ;
165+ execSync ( "uv --version" , {
166+ encoding : "utf8" ,
167+ stdio : [ "pipe" , "pipe" , "pipe" ] ,
168+ } ) ;
171169 } catch {
172- console . warn (
173- "Warning: pydantic not found on the host Python.\n" +
174- "The Codex agent will attempt to install it, but you can also run:\n" +
175- " pip install 'pydantic>=2.9.0'" ,
176- ) ;
170+ throw new Error ( "uv is required and was not found on PATH." ) ;
177171 }
178172}
179173
@@ -189,6 +183,23 @@ function setupWorkspace(workDir: string, opts: CodegenOptions): void {
189183 // Create the output directory the agent writes into
190184 fs . mkdirSync ( path . join ( workDir , "generated" ) , { recursive : true } ) ;
191185
186+ // Create a venv with pydantic via uv so that both the agent and our
187+ // host-side verification have a working Python regardless of whether
188+ // the system Python is Nix-managed / immutable.
189+ log ( opts , "Creating Python venv with pydantic..." ) ;
190+ execSync ( "uv venv .venv" , { cwd : workDir , stdio : "pipe" } ) ;
191+ execSync ( "uv pip install 'pydantic>=2.9.0'" , {
192+ cwd : workDir ,
193+ stdio : "pipe" ,
194+ timeout : 120_000 ,
195+ env : { ...process . env , VIRTUAL_ENV : `${ workDir } /.venv` } ,
196+ } ) ;
197+ const version = execSync (
198+ '.venv/bin/python -c "import pydantic; print(pydantic.VERSION)"' ,
199+ { cwd : workDir , encoding : "utf8" , stdio : [ "pipe" , "pipe" , "pipe" ] } ,
200+ ) . trim ( ) ;
201+ log ( opts , `Installed pydantic ${ version } in workspace venv` ) ;
202+
192203 // Minimal git init so Codex is happy (belt-and-suspenders alongside
193204 // skipGitRepoCheck)
194205 try {
@@ -220,7 +231,7 @@ function runVerification(workDir: string): VerifyResult {
220231
221232 try {
222233 const output = execSync (
223- "python3 verify_schema.py schema.json generated" ,
234+ ".venv/bin/python verify_schema.py schema.json generated" ,
224235 {
225236 cwd : workDir ,
226237 encoding : "utf8" ,
0 commit comments