Skip to content

Codex

Codex is an AI coding assistant provided by OpenAI. It can inspect and modify files, execute commands, and work with existing codebases from the terminal.

On SAV infrastructure, Codex runs in a Singularity/Apptainer container on an HPC login node. It connects directly to OpenAI; no vLLM server or SSH tunnel is required.

Quickstart

From the directory containing your project, run:

cd ~/my-project
~/llm/codex.sh

The launcher displays:

Codex session:

  1) Continue last session
  2) Start new session
  3) Select previous session
  4) Exit

Select [1]:

Press Enter to resume the latest session, or select another option.

Launcher

Save the launcher shown below as ~/llm/codex.sh and make it executable:

chmod +x ~/llm/codex.sh

The launcher uses two host account files to resolve your UID and group inside the container. Create them once:

mkdir -p ~/llm
getent passwd root "$USER" > ~/llm/.container_passwd
getent group root "$(id -gn)" > ~/llm/.container_group

Regenerate these files if your account or primary group changes. Do not run the launcher as root unless you deliberately want root's authentication and session history.

Authentication

Codex connects to OpenAI. Authenticate using the method supported by your Codex installation and account, typically by starting Codex and following its sign-in instructions. The launcher binds $HOME, so configuration and session data persist between runs. No local vLLM API key is required.

Usage

codex.sh [WORKSPACE] [MODE] [-B HOST[:CONTAINER]] [-- CODEX_ARGS...]

  WORKSPACE    Working directory (default: current directory)
  MODE         --continue, --new, --resume, or --list
  -B, --bind   Additional bind mount (repeatable)
  -- ARGS      Additional arguments passed to Codex

Examples:

# Open the menu in the current directory.
~/llm/codex.sh

# Work in another directory and start a new session.
~/llm/codex.sh /myproject/path --new

# Resume the most recent session.
~/llm/codex.sh --continue

# Open the session selector.
~/llm/codex.sh --resume

# Mount additional directories.
~/llm/codex.sh /myproject/path \
    -B /project/<account_ID>:/project/<account_ID> \
    -B /scratch/<account_ID>:/scratch/<account_ID>

# Display the Codex CLI help.
~/llm/codex.sh --new -- --help

Session modes

Launcher mode Codex arguments Effect
--continue --no-daemon resume --last Resume the latest session
--new --no-daemon Start a new session
--resume --no-daemon resume Open the session selector
--list --no-daemon resume Alias for the session selector
(none) Interactive menu Prompt for a mode

--continue and --resume are launcher options, not native Codex options. The native Codex session interface uses the resume subcommand. The --no-daemon option is used because some containerized installations lack the complete background-server package. Check codex --help and codex resume --help if your installed version behaves differently.

The launcher

The script checks the image and workspace, parses session options and additional binds, loads Singularity where necessary, and launches Codex with the selected arguments. The container image path and Slurm bind path can be configured without modifying the script.

~/llm/codex.sh
#!/bin/bash
set -euo pipefail

# ----------------------------------------------------------------------
# Configuration
# ----------------------------------------------------------------------

CODEX_SIF="${CLAUDE_SIF:-/storage-apps/containers/vllm/x86_64/Claude_code_x86_64_Nov2026_perun.sif}"             # Perun
#CODEX_SIF="${CLAUDE_SIF:-/apps/images/vllm/x86_64/Claude_code_x86_64_Nov2026_devana.sif}"                       # Devana

if [[ -z "$CODEX_SIF" || ! -f "$CODEX_SIF" ]]; then
    echo "ERROR: CODEX_SIF is not set or the image does not exist." >&2
    echo "Example: export CODEX_SIF=/path/to/Codex.sif" >&2
    exit 1
fi

USER_HOME="$HOME"
USER_LLM_DIR="$HOME/llm"

WORKSPACE="$PWD"
WORKSPACE_SET=0
MODE=""

EXTRA_ARGS=()
EXTRA_BINDS=()

# ----------------------------------------------------------------------
# Usage
# ----------------------------------------------------------------------

usage() {
    cat <<EOF
Usage:
  $(basename "$0") [WORKSPACE] [MODE] [OPTIONS] [-- CODEX_ARGS...]

Modes:
  --continue       Continue the last session
  --new            Start a new session
  --resume         Select a previous session
  --list           Open the session picker

Options:
  -B, --bind HOST[:CONTAINER]
                   Add an additional bind mount (repeatable)
  -h, --help       Show this help

Examples:
  $(basename "$0")
  $(basename "$0") /project/myproject
  $(basename "$0") --continue
  $(basename "$0") /project/myproject --new
  $(basename "$0") -B /data:/data
  $(basename "$0") /project/myproject -B /data:/data -- --model gpt-5.1-codex

Default bind mounts:
  \$HOME:\$HOME
  /project/p2075-26-2:/project/p2075-26-2
  /run/munge:/run/munge
  /var/spool/slurmd/conf-cache:/etc/slurm
  \$HOME/llm/.container_passwd:/etc/passwd
  \$HOME/llm/.container_group:/etc/group
EOF
}

# ----------------------------------------------------------------------
# Parse arguments
# ----------------------------------------------------------------------

while [[ $# -gt 0 ]]; do
    case "$1" in
        --continue|--new|--resume|--list)
            MODE="$1"
            shift
            ;;

        -B|--bind)
            if [[ $# -lt 2 ]]; then
                echo "ERROR: $1 requires a bind specification." >&2
                exit 1
            fi

            EXTRA_BINDS+=("$2")
            shift 2
            ;;

        --)
            shift
            EXTRA_ARGS+=("$@")
            break
            ;;

        -h|--help)
            usage
            exit 0
            ;;

        -*)
            echo "ERROR: Unknown option: $1" >&2
            usage >&2
            exit 1
            ;;

        *)
            if [[ "$WORKSPACE_SET" -eq 0 ]]; then
                WORKSPACE="$1"
                WORKSPACE_SET=1
            else
                echo "ERROR: Unexpected argument: $1" >&2
                usage >&2
                exit 1
            fi
            shift
            ;;
    esac
done

# ----------------------------------------------------------------------
# Validate workspace
# ----------------------------------------------------------------------

WORKSPACE="$(realpath "$WORKSPACE")"

if [[ ! -d "$WORKSPACE" ]]; then
    echo "ERROR: Workspace does not exist: $WORKSPACE" >&2
    exit 1
fi

# ----------------------------------------------------------------------
# Interactive session menu
# ----------------------------------------------------------------------

case "$MODE" in
    --continue)
        CODEX_ARGS=(--no-daemon resume --last)
        ;;

    --new)
        CODEX_ARGS=(--no-daemon)
        ;;

    --resume|--list)
        CODEX_ARGS=(--no-daemon resume)
        ;;

    "")
        if [[ ! -t 0 ]]; then
            echo "Not a terminal. Pass --continue, --new," >&2
            echo "--resume or --list explicitly." >&2
            exit 1
        fi

        echo
        echo "Codex session:"
        echo
        echo "  1) Continue last session"
        echo "  2) Start new session"
        echo "  3) Select previous session"
        echo "  4) List sessions"
        echo "  5) Exit"
        echo

        read -r -p "Select [1]: " CHOICE || CHOICE=1

        # Pressing Enter selects the default.
        CHOICE=${CHOICE:-1}

        case "$CHOICE" in
            1)
                CODEX_ARGS=(--no-daemon resume --last)
                ;;
            2)
                CODEX_ARGS=(--no-daemon)
                ;;
            3|4)
                CODEX_ARGS=(--no-daemon resume)
                ;;
            5)
                exit 0
                ;;
            *)
                echo "Invalid selection." >&2
                exit 1
                ;;
        esac
        ;;

    *)
        echo "Unknown option: $MODE" >&2
        usage >&2
        exit 1
        ;;
esac

# Append additional Codex arguments.
CODEX_ARGS+=("${EXTRA_ARGS[@]}")

# ----------------------------------------------------------------------
# Default bind mounts
# ----------------------------------------------------------------------

BINDS=(
    "$WORKSPACE:$WORKSPACE"
    "$USER_HOME:$USER_HOME"
    "/project/p2075-26-2:/project/p2075-26-2"
    "/run/munge:/run/munge"
    "/var/spool/slurmd/conf-cache:/etc/slurm"
    "$USER_LLM_DIR/.container_passwd:/etc/passwd"
    "$USER_LLM_DIR/.container_group:/etc/group"
)

# Append user-defined bind mounts.
for bind in "${EXTRA_BINDS[@]}"; do
    BINDS+=("$bind")
done

# ----------------------------------------------------------------------
# Load Singularity
# ----------------------------------------------------------------------

if command -v module >/dev/null 2>&1; then
    module load singularity
fi

if ! command -v singularity >/dev/null 2>&1; then
    echo "ERROR: singularity command not found." >&2
    exit 1
fi

# Check architecture.
if [[ "$(uname -m)" != "x86_64" ]]; then
    echo "ERROR: This Codex image requires x86_64." >&2
    exit 1
fi

# ----------------------------------------------------------------------
# Build bind arguments
# ----------------------------------------------------------------------

SINGULARITY_BINDS=()

for bind in "${BINDS[@]}"; do
    SINGULARITY_BINDS+=(--bind "$bind")
done

# ----------------------------------------------------------------------
# Launch Codex
# ----------------------------------------------------------------------

singularity exec \
    "${SINGULARITY_BINDS[@]}" \
    --pwd "$WORKSPACE" \
    --env "PATH=/usr/local/bin:/opt/agent_env/bin:/opt/slurm/bin:/opt/slurm/sbin:$HOME/.local/bin:/usr/bin:/bin" \
    "$CODEX_SIF" \
    bash -lc 'exec codex "$@"' -- "${CODEX_ARGS[@]}"

Devana slurm bind

On devana slurm needs to be bind followingly -- bind /etc/slurm:/etc/slurm & --env "PATH=/usr/local/bin:/opt/agent_env/bin:$HOME/.local/bin:/usr/bin:/bin"

Running agents responsibly

Codex can execute commands and modify files. Commands launched directly by the agent run on the login node, not on a compute node. Submit computationally intensive builds, tests, and simulations through Slurm.

For example, instruct the agent:

Compile the software and run its test suite. Submit the build and tests
through Slurm to the CPU partition using the appropriate project account.
Check the job status and report the output.

Compute allocation

Codex may submit jobs that consume your project's allocation. Specify the account, partition, resource requirements, and walltime. Review running jobs using squeue -u "$USER".

File modifications

Codex edits real files. Work inside the intended project directory, keep changes under version control, and review modifications before committing or executing generated code.

Bind mounts

The launcher binds the workspace and home directory. It also binds available Munge and Slurm resources and the optional host account files.

Bind Purpose
$WORKSPACE:$WORKSPACE Access to the project directory
$HOME:$HOME Persistent authentication, configuration, and sessions
/run/munge:/run/munge Munge authentication socket directory
$SLURM_CONF_DIR:/etc/slurm Slurm client configuration
.container_passwd:/etc/passwd Host account resolution
.container_group:/etc/group Host group resolution

Additional bind mounts can be supplied with repeated -B options:

~/llm/codex.sh /myproject/path \
    -B /project/<account_ID>:/project/<account_ID> \
    -B /scratch/<account_ID>:/scratch/<account_ID>

The source paths must exist and be accessible on the host. Binding a workspace does not automatically expose other directories outside it.

Troubleshooting

Codex image not found

Check the configured path:

printf '%s\n' "$CODEX_SIF"
ls -lh "$CODEX_SIF"

If CODEX_SIF is unset, export the image path as described above.

unexpected argument '--continue' found

--continue is not a native Codex option. Use the launcher option --continue, which translates to codex --no-daemon resume --last. Do not pass --continue directly to the Codex executable.

`this CLI has no complete local package`

Some container images contain a CLI that cannot start its background server. The installed CLI may recommend --no-daemon. The launcher uses this option for new and resumed sessions. If it still fails, inspect the installation or rebuild the image with a complete CLI.

Check the installed command-line interface:

apptainer exec "$CODEX_SIF" codex --help
apptainer exec "$CODEX_SIF" codex resume --help

`codex: command not found`

Inspect the executable inside the container:

apptainer exec "$CODEX_SIF" sh -c 'command -v codex'

If the executable is elsewhere, adjust the container PATH or the final command in the launcher.

Slurm commands fail inside the container

Check the resources on the host:

ls -ld /run/munge "$SLURM_CONF_DIR"
ls -l ~/llm/.container_passwd ~/llm/.container_group

Verify that the Slurm client is available in the container:

apptainer exec \
    --bind /run/munge:/run/munge \
    --bind "$SLURM_CONF_DIR:/etc/slurm" \
    --env 'PATH=/opt/slurm/bin:/opt/slurm/sbin:/usr/bin:/bin' \
    "$CODEX_SIF" squeue -u "$USER"
Symptom Possible cause
squeue: command not found Slurm binaries absent from PATH
Invalid user/group Missing or outdated account bind files
Munge authentication error Munge socket unavailable or not mounted
Unable to contact controller Wrong Slurm configuration or connectivity issue
Bind mount error Source path missing or inaccessible

Codex cannot access project files

Check directory permissions and pass additional paths with -B:

ls -ld "$PWD"
~/llm/codex.sh "$PWD" -B /project/shared:/project/shared

A session cannot be resumed

Session history is stored under the user's home directory. Use the same Unix account and home directory as when the session was created. To select a previous session, run:

~/llm/codex.sh --resume

A session created as a regular user will not necessarily be visible when the launcher is run as root.

Reference

Task Command
Interactive menu ~/llm/codex.sh
Continue last session ~/llm/codex.sh --continue
Start new session ~/llm/codex.sh --new
Select previous session ~/llm/codex.sh --resume
Session selector alias ~/llm/codex.sh --list
Another workspace ~/llm/codex.sh ~/my-project
Additional bind mount ~/llm/codex.sh -B /data:/data
Codex help ~/llm/codex.sh --new -- --help
Variable Purpose
CODEX_SIF Path to the Codex Singularity image
SLURM_CONF_DIR Host Slurm configuration directory
Created by: Marek Štekláč