From 6a5ce586eb16d035abf166e77a6028290fd92010 Mon Sep 17 00:00:00 2001 From: ReachableCEO Date: Wed, 15 Oct 2025 17:29:06 -0500 Subject: [PATCH] refactor(input): bake codex cli runtime --- input/AGENTS.md | 14 ++++----- input/Docker/Dockerfile | 4 ++- input/Docker/docker-compose.yml | 3 +- input/Docker/watch_and_customize.py | 44 +++++++++++------------------ input/README.md | 6 ++-- 5 files changed, 32 insertions(+), 39 deletions(-) diff --git a/input/AGENTS.md b/input/AGENTS.md index af09785..633a6e3 100644 --- a/input/AGENTS.md +++ b/input/AGENTS.md @@ -20,12 +20,12 @@ cd input/Docker ./run-input-processor.sh up -d ``` -Environment variables you can pass before the command: -- `CODEX_COMMAND_TEMPLATE` – override the Codex CLI invocation for the resume customization run (defaults to `codex prompt --input {prompt} --output {output} --format markdown`). -- `CODEX_NORMALIZER_COMMAND_TEMPLATE` – optional override for the job-description normalization run (defaults to the same value as `CODEX_COMMAND_TEMPLATE`). -- `POLL_INTERVAL_SECONDS` – watcher polling cadence (default `5`). -- `CODEX_TIMEOUT_SECONDS` – hard timeout for Codex calls (default `600`). -- `CODEX_CONFIG_DIR` – optional override for the host directory that should mount into `/home/codex/.codex`. +- Environment variables you can pass before the command: + - `POLL_INTERVAL_SECONDS` – watcher polling cadence (default `5`). + - `CODEX_TIMEOUT_SECONDS` – hard timeout for Codex calls (default `600`). + - `CODEX_CONFIG_DIR` – optional override for the host directory that should mount into `/home/codex/.codex`. + +The container bundles the Codex CLI and expects the caller to mount their `~/.codex` directory for credentials. Stop or inspect the stack with: @@ -44,4 +44,4 @@ cd input/Docker ## Troubleshooting - If Codex CLI fails, the job description moves to `ForCustomizing/failed/`. Check container logs, adjust the Markdown, then requeue it. - Fatal errors (multiple resumes, multiple job descriptions, missing template, or missing Codex binary) stop the container. Resolve the issue and restart via the wrapper. -- To change the Codex command format, pass a quoted template (e.g., `CODEX_COMMAND_TEMPLATE='codex run --input {prompt} --output {output}' ./run-input-processor.sh up -d'`). The template must include `{prompt}` and `{output}` placeholders. +- The watcher logs the exact `codex prompt --input … --output … --format markdown` command before each invocation; inspect container logs if troubleshooting is needed. diff --git a/input/Docker/Dockerfile b/input/Docker/Dockerfile index 3966a4e..555b026 100644 --- a/input/Docker/Dockerfile +++ b/input/Docker/Dockerfile @@ -15,7 +15,9 @@ RUN apt-get update \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* -RUN npm install --location=global codex-cli || true +# Install the official Codex CLI so the container can invoke `codex prompt`. +# The CLI expects credentials/configuration from the mounted ~/.codex directory. +RUN npm install --location=global @openai/codex RUN groupadd -r codex && \ useradd -r -m -g codex -s /bin/bash codex diff --git a/input/Docker/docker-compose.yml b/input/Docker/docker-compose.yml index 016fa3b..10789c3 100644 --- a/input/Docker/docker-compose.yml +++ b/input/Docker/docker-compose.yml @@ -12,8 +12,6 @@ services: PGID: "${LOCAL_GID:-1000}" POLL_INTERVAL_SECONDS: "${POLL_INTERVAL_SECONDS:-5}" CODEX_TIMEOUT_SECONDS: "${CODEX_TIMEOUT_SECONDS:-600}" - CODEX_COMMAND_TEMPLATE: "${CODEX_COMMAND_TEMPLATE:-codex prompt --input {prompt} --output {output} --format markdown}" - CODEX_NORMALIZER_COMMAND_TEMPLATE: "${CODEX_NORMALIZER_COMMAND_TEMPLATE:-codex prompt --input {prompt} --output {output} --format markdown}" volumes: - ../ForCustomizing/inbox:/workspace/inbox - ../ForCustomizing/outbox:/workspace/outbox @@ -22,3 +20,4 @@ services: - ../resume:/workspace/resume:ro - ../templates:/templates:ro - ${CODEX_CONFIG_DIR:-/workspace/.codex}:/home/codex/.codex + - /etc/localtime:/etc/localtime:ro diff --git a/input/Docker/watch_and_customize.py b/input/Docker/watch_and_customize.py index ebdffcd..dac7fc0 100644 --- a/input/Docker/watch_and_customize.py +++ b/input/Docker/watch_and_customize.py @@ -13,7 +13,6 @@ from __future__ import annotations import logging import os -import shlex import shutil import subprocess import time @@ -32,17 +31,9 @@ TEMPLATES_DIR = Path("/templates") TEMPLATE_CACHE = Path("/tmp/templates") PROMPT_TEMPLATE = TEMPLATES_DIR / "ResumeCustomizerPrompt.md" PROMPT_TEMPLATE_EXAMPLE = TEMPLATES_DIR / "ResumeCustomizerPrompt.md.example" -NORMALIZER_TEMPLATE = Path('/app/JobDescriptionNormalizerPrompt.md') +NORMALIZER_TEMPLATE = Path("/app/JobDescriptionNormalizerPrompt.md") POLL_INTERVAL_SECONDS = int(os.environ.get("POLL_INTERVAL_SECONDS", "5")) -CODEX_COMMAND_TEMPLATE = os.environ.get( - "CODEX_COMMAND_TEMPLATE", - "codex prompt --input {prompt} --output {output} --format markdown", -) -CODEX_NORMALIZER_COMMAND_TEMPLATE = os.environ.get( - "CODEX_NORMALIZER_COMMAND_TEMPLATE", - CODEX_COMMAND_TEMPLATE, -) CODEX_TIMEOUT_SECONDS = int(os.environ.get("CODEX_TIMEOUT_SECONDS", "600")) RESOLVED_PROMPT_TEMPLATE: Path | None = None @@ -193,20 +184,19 @@ def slugify(component: str) -> str: return "-".join(parts) -def run_codex(prompt_path: Path, output_path: Path, command_template: str) -> None: - """Execute the Codex CLI using the provided command template.""" - command_text = command_template.format( - prompt=str(prompt_path), - output=str(output_path), - ) - logging.info("Running Codex CLI command: %s", command_text) - - try: - command = shlex.split(command_text) - except ValueError as exc: - raise FatalConfigurationError( - f"Unable to parse Codex command template into arguments: {exc}" - ) from exc +def run_codex(prompt_path: Path, output_path: Path) -> None: + """Execute the Codex CLI.""" + command = [ + "codex", + "prompt", + "--input", + str(prompt_path), + "--output", + str(output_path), + "--format", + "markdown", + ] + logging.info("Running Codex CLI command: %s", " ".join(command)) try: subprocess.run( @@ -217,7 +207,7 @@ def run_codex(prompt_path: Path, output_path: Path, command_template: str) -> No ) except FileNotFoundError as exc: raise FatalConfigurationError( - f"Executable not found while running Codex CLI command: {command[0]}" + "Codex CLI executable 'codex' not found in PATH" ) from exc except subprocess.TimeoutExpired as exc: raise RuntimeError("Codex CLI timed out") from exc @@ -301,7 +291,7 @@ def normalize_job_description(job_file: Path) -> NormalizedJobDescription: prompt_path.write_text(prompt_text, encoding="utf-8") output_path = tmp_dir / "normalize_output.md" - run_codex(prompt_path, output_path, CODEX_NORMALIZER_COMMAND_TEMPLATE) + run_codex(prompt_path, output_path) normalized_text = output_path.read_text(encoding="utf-8").strip() return parse_normalized_output(normalized_text) @@ -356,7 +346,7 @@ def process_job(job_file: Path) -> None: prompt_path.write_text(prompt_text, encoding="utf-8") output_path = tmp_dir / "codex_output.md" - run_codex(prompt_path, output_path, CODEX_COMMAND_TEMPLATE) + run_codex(prompt_path, output_path) generated_output = out_dir / output_filename counter = 1 diff --git a/input/README.md b/input/README.md index 71a0348..92282e5 100644 --- a/input/README.md +++ b/input/README.md @@ -24,9 +24,11 @@ The watcher lives in `input/Docker/`: - `templates/ResumeCustomizerPrompt.md.example` ships with default resume-customization instructions. Copy it to `ResumeCustomizerPrompt.md` to override. - The `.gitignore` in `templates/` keeps local overrides out of version control. +### Codex CLI +- The container image installs the official Codex CLI and expects credentials/configuration from the mounted `~/.codex` directory on the host. +- No additional command-line customization is required; the watcher invokes `codex prompt --input … --output … --format markdown` internally for both passes. + ### Key Environment Variables -- `CODEX_COMMAND_TEMPLATE` – format string for the resume-customization Codex run (placeholders: `{prompt}`, `{output}`). -- `CODEX_NORMALIZER_COMMAND_TEMPLATE` – optional override for the normalization Codex run (defaults to `CODEX_COMMAND_TEMPLATE`). - `POLL_INTERVAL_SECONDS` – watch loop delay (defaults to 5). - `CODEX_TIMEOUT_SECONDS` – wall-clock timeout for each Codex call (defaults to 600). - `CODEX_CONFIG_DIR` – host path to mount as `/home/codex/.codex` (defaults to `${HOME}/.codex` via the wrapper).