Skip to content

Codex Runner

Codex is the AI CLI tool that v16 uses for code analysis. It runs as a subprocess: v16 constructs a codex exec command, passes it a source directory, and reads JSON events from its stdout.

How Codex is invoked

v16/codex_runner.py handles all Codex invocations. The basic pattern:

  1. Build the codex exec --json ... command with the source path and task prompt
  2. Start the subprocess
  3. Stream stdout line by line
  4. Parse each line as a JSON event
  5. Forward events to the caller

The --json flag makes Codex emit structured JSON rather than human-readable text, which is what codex_runner.py parses.

Container isolation

In the default configuration, Codex doesn't run in the host process directly — it runs inside a Docker container. This provides:

  • Isolation — Codex (and any code it executes) can't access the host filesystem beyond the mounted source directory
  • Reproducibility — the Codex version and environment are fixed in the container image
  • Safety — a bug in Codex can't affect the host or other scans

The isolation wrapper is scripts/codex-in-target-container.sh, and VEGA_V16_CODEX_BIN defaults to this script. The script runs Codex inside the vega-codex-runner Docker image.

Building the Codex container image

scripts/build-codex-runner-image.sh

This builds the vega-codex-runner:latest image from docker/codex-runner/Dockerfile. The image includes Debian, build tools, ripgrep (for fast code searching), and the codex npm package.

Bypassing the container (for debugging)

During local debugging, you can skip the Docker container by pointing VEGA_V16_CODEX_BIN at a locally installed codex binary:

VEGA_V16_CODEX_BIN=codex uvicorn app.main:app --reload --reload-dir app

This is faster than building the image but removes the isolation benefits.

Key files

File What it does
v16/codex_runner.py Builds Codex commands, runs the subprocess, parses stdout
scripts/codex-in-target-container.sh Shell entry point for the Docker isolation wrapper
scripts/codex-in-target-container.py Python script that constructs the full docker run command
app/projects/codex_container_manager.py Docker container lifecycle: labels, cleanup, metadata
docker/codex-runner/Dockerfile The Codex sandbox image

In AWS (ECS runner)

When a scan runs as an ECS Fargate task:

  • The vega-v16-runner container image includes Node.js and the codex npm package directly (no separate Docker-in-Docker).
  • VEGA_V16_CODEX_BIN is set to the codex binary in the PATH.
  • All AI calls from Codex are routed through OPENAI_BASE_URL pointing at vega-llm-proxy.

The runner receives a scan-scoped proxy token and sets it as the Bearer token for Codex's API calls. Codex calls the proxy as if it were OpenAI.

Debugging Codex failures

Codex fails to start: 1. Is Docker running? The container isolation wrapper needs Docker. 2. Is the vega-codex-runner image built? Run scripts/build-codex-runner-image.sh. 3. Check VEGA_V16_CODEX_BIN — is it pointing to the right script or binary?

Codex starts but returns no findings: 1. Check v16-events.jsonl in the scan artifacts — did Codex emit any events? 2. Check v16-debug-bundle.zip — this contains the full Codex working state, including prompts and responses. 3. Check v16-report.json for a structured summary of what Codex analyzed.

Codex fails with authentication errors in AWS: 1. Is OPENAI_BASE_URL set to the LLM proxy URL? 2. Is the scan-scoped proxy token present in the runner environment? 3. Check LLM proxy logs for the incoming request.

Stale Codex containers accumulating locally: app/projects/codex_container_manager.py tracks and cleans up Codex containers. On API startup/shutdown, stale containers are removed. If you have orphaned containers, inspect them with docker ps -a | grep vega-codex and remove manually if needed.