Tools Reference¶
This repository revolves around three utility scripts:
refresh.pyrefreshes local credentials and can copy them to a remote hostlaunch.pystarts Codex or Claude Code inside a containerbuild.pybuilds the container image itself
You’ll usually only need refresh.py and launch.py.
Use build.py only if you want to build your own image rather than use
the hosted one.
How to get the scripts¶
You will need refresh.py on the local machine, and launch.py on
whatever machine (local and/or remote) you want to run a container on.
Two main ways of getting them.
Clone the repo, say to your home directory. This is the recommended method, because you can always run
git pull origin mainto update the scripts.git clone https://github.com/nichd-bspc/llm ~/llm
Or manually download them, say to a
~/bindirectory:# on local machine curl -fSsL -o ~/bin/launch.py https://raw.githubusercontent.com/nichd-bspc/llm/main/launch.py curl -fSsL -o ~/bin/refresh.py https://raw.githubusercontent.com/nichd-bspc/llm/main/refresh.py chmod +x ~/bin/launch.py ~/bin/refresh.py # on remote we only need launch.py curl -fSsL -o ~/bin/launch.py https://raw.githubusercontent.com/nichd-bspc/llm/main/launch.py chmod +x ~/bin/launch.py
Then either call them directly with the full path name, or add them to your
PATH. For example, if you cloned the repo to your ome directory, you would
add this to your ~/.bashrc (or wherever you set your $PATH
variable):
export PATH="$PATH:~/llm"
Note
See Julia Evans’ excellent writeup on
$PATH and adding to it if you’re unfamiliar with the concept.
Tip
You know it’s working if you open a new terminal and can run launch.py
-h and/or refresh.py -h to see the help.
refresh.py¶
Refreshes credentials locally, and optionally copies them to a remote host.
Refreshes Codex authentication (
~/.codex/auth.json). This is mounted inside running Codex containers, so they will see the new credentials when refreshed.Refreshes AWS SSO credentials and exports them as JSON to
~/.aws/credentials.json. This is used by thellm-exportprofile viacredential_processso containers can read live credentials without a restart; see How Bedrock credentials reach the container for why this indirection exists.Converts the OpenAI auth tokens in
~/.codex.auth.jsonto a Pi-compatible format and stores in~/.pi/agent/auth.jsonso that Pi can use ChatGPT Enterprise within a container. This needs the auth-reload extension installed.Optionally pushes refreshed credentials to a remote host (such as NIH’s Biowulf).
Optionally pushes entire config directories to remote.
Optionally prints Bedrock bearer-token exports for tools that do not use the AWS SDK.
Note
If credentials expire mid-session, you can run refresh.py and then
immediately re-try the prompt without exiting the agent or the container.
This works on a remote, too – using the --remote option will push the
credentials to the remote, and a running container on the remote will
automatically pick up the refreshed credentials.
Examples¶
Refresh codex & aws locally:
refresh.py
Refresh all and push credentials to a remote system. This exports AWS session
credentials as ~/.aws/credentials.json and configures the
llm-export profile on the remote:
refresh.py --remote biowulf.nih.gov
Only refresh codex, and push to remote system:
refresh.py --kind codex --remote biowulf.nih.gov
Refresh all, push credentials as well as entire agent config dirs to remote system:
refresh.py --full --remote biowulf.nih.gov
See what files will be pushed with --full:
refresh.py --show-files
Export a temporary Bedrock token, which can be used for other tools that don’t support AWS SSO:
eval "$(./refresh.py --bedrock-export)"
launch.py¶
Runs the agent inside a container, assuming credentials are already available, e.g., by running refresh.py.
Starts
codex,claude,pi, or an interactive shell in a containerPasses through mounts, env vars, cert bundles, and optional conda environments
Detects Podman vs Singularity, or accepts an explicit backend
Defaults to automatically pulling the latest container for the launched harness, published by this repo to GitHub Container Registry (https://ghcr.io/nichd-bspc/llm). Each harness has its own
latesttag (codex-latest,claude-latest,pi-latest) that only moves when that harness changes version, so you don’t pull a fresh image every day when the harness is unchanged. Theshellsubcommand uses the overalllatesttag. Use--tagto pick a different tag (e.g.--tag latestfor the latest overall image, or--tag codex-0.125.0to pin a version), or--image-name/--sif-pathfor full control.By default, mounts the current working directory and only the credential/config paths relevant to the called tool
Default config and credential mounts¶
By default, launch.py mounts the current working directory.
Also by defaut, it mounts the following host paths in a tool-specific manner
into /home/devuser inside the container when they exist:
launch.py codex:~/.codexlaunch.py claude:~/.claudeand~/.claude.jsonlaunch.py pi:~/.pilaunch.py shell:~/.codex,~/.claude,~/.claude.json, and~/.pi
When Amazon Bedrock is enabled for the effective container environment,
~/.aws is also mounted under these circumstances:
claude: whenCLAUDE_CODE_USE_BEDROCK=1pi: whenPI_USE_BEDROCK=1shell: whenCLAUDE_CODE_USE_BEDROCK=1orPI_USE_BEDROCK=1
If ~/.aws/credentials.json exists, launch.py automatically uses
the llm-export profile for Bedrock unless AWS_PROFILE is already set.
If host proxy variables are set, launch.py passes them through to the
container.
See Configuration and credential files for what those files and directories contain.
Example usage¶
Note
Unless noted otherwise, these examples use Codex for simplicity. Replace
codex with claude, pi, or shell as needed.
Basic usage¶
Note
Any arguments that come before the tool (codex/claude/pi) are interpreted as arguments for launch.py.
Any arguments that come after the tool are interpreted as arguments for the tool.
For example, this shows the help for launch.py (note the -h comes before codex):
launch.py -h codex
But this shows the help for codex, as run through the container (note the -h comes after codex):
launch.py codex -h
Run codex, detecting container runtime automatically (Podman on Mac, Singularity on Linux):
launch.py codex
Run a shell for debugging – this will mount credentials for all supported agents:
launch.py shell
Resume a session:
launch.py codex --resume 019dd08c-a96f-7090-8708-8a4f4cfa8834
One-shot prompt with an attached image and then exit:
launch.py codex exec \
-i ./image.png \
-o out.json \
-- \
"extract the text from this image and return as JSON"
Mounts and read-only¶
Let the container see something outside the working directory:
launch.py --mount /data/experiment1 codex
Mount a directory read-only inside the container:
launch.py --mount /data/experiment1:/data/experiment1:ro codex
Mount the current working directory as read-only, so the agent can read but not modify your files:
launch.py --global-read-only codex
Keep the working directory writable but protect a single subdirectory. The
--ro path is re-mounted read-only on top of the read-write workspace, so its
contents remain readable but cannot be modified:
launch.py --ro data codex
--ro takes a path relative to the current working directory (or an absolute
path inside it) and may be repeated to protect several subdirectories.
Hide a sensitive subdirectory of the working directory from the container. The rest of the working directory is mounted as usual, but the masked path is shadowed by an empty, read-only directory so its contents are not visible inside the container:
launch.py --mask secrets codex
--mask takes a path relative to the current working directory (or an
absolute path inside it) and may be repeated to mask several subdirectories.
To keep a default set of extra mounts, put them in
LLM_DEVCONTAINER_MOUNTS as a shell-style (space-separated) list:
export LLM_DEVCONTAINER_MOUNTS="$HOME/data /scratch/shared:/scratch/shared:ro"
# equivalent of the following, but will happen by default:
# launch.py --mount $HOME/data --mount /scratch/shared:/scratch/shared:ro
Mount a conda env into the container and prepend it to the path so the agent can use it (only works on Linux, but see Conda envs only work on Linux for a workaround):
launch.py --conda-env my-env codex
Using --conda-env is a shortcut for the following:
launch.py \
--mount $(conda info --base)/envs/my-env \
--prepend-path ~/conda/envs/my-env/bin \
codex
Environment and certificates¶
Provide additional environment variables to the container, or override what’s in the environment:
launch.py \
--env OMP_NUM_THREADS=1 \
--env HOME=/tmp \
codex
Provide a certificates file you’ve previously downloaded to allow enterprise TLS interception (see Enterprise TLS certificates):
launch.py --certs ~/certs.pem codex
Backend and debugging¶
Force podman instead of Singularity:
launch.py --backend podman codex
Print out the command to be run as composed by launch.py and then exit
without running. Useful for debugging (see also Using dry-run for debugging):
launch.py --dry-run codex
When developing locally or using other containers, specify the image name (Podman) or SIF name (Singularity):
# after running build.py locally
launch.py --image-name llm-devcontainer codex
# or another published image
launch.py --image-name quay.io/org/container codex
# or on Linux host, defaults to Singularity:
launch.py --sif-name llm.sif codex
To stay on the published images but choose a different tag, use --tag:
# use the latest overall image instead of the per-harness latest
launch.py --tag latest codex
# pin a specific harness version
launch.py --tag codex-0.125.0 codex
Environment variables created by launch.py¶
Supply additional env vars at the command line with --env NAME=VALUE. This
can be used to override defaults. The following environment variables are set by
default in the container:
Base environment:
HOME– set to/home/devuserUSER,LOGNAME,USERNAME– set todevuserTOOL– the subcommand being run (e.g.,codex,claude,pi); this is only used for informationHOST_MOUNT_DIR– the current working directory on the hostPATH– constructed from the base Ubuntu PATH plus/home/devuser/.local/bin, with optional prepends from--conda-envor--path-prepend
Tool-specific inherited variables:
For
claudeandshell: All host environment variables starting withCLAUDE_CODEorANTHROPIC_For
piandshell: All host environment variables starting withPI_For
claude,pi, andshell: When Bedrock is enabled (viaCLAUDE_CODE_USE_BEDROCK=1orPI_USE_BEDROCK=1): Host environment variables starting withAWS_. IfAWS_PROFILEis set or the automaticllm-exportprofile is in use, don’t sendAWS_ACCESS_KEY_IDorAWS_SESSION_TOKENto the container so thatcredential_processin~/.aws/configworks properly.
Certificate variables (when --certs is provided):
When --certs (or LLM_DEVCONTAINER_CERTS) is provided (see
Enterprise TLS certificates), that file is mounted into the container at
/tmp/llm-devcontainer-cert.pem and the following env vars are set,
pointing to that path:
SSL_CERT_FILEGIT_SSL_CAINFOAWS_CA_BUNDLEREQUESTS_CA_BUNDLENODE_EXTRA_CA_CERTSCURL_CA_BUNDLE
build.py¶
Builds the local Podman image.
Builds a Podman image from this repo’s
DockerfileSupports
--no-cache,--dry-run,--image-name,--arch, and--certs
./build.py
./build.py --no-cache
See Developers. Image maintainers should keep a full checkout
and run ./build.py from the repo root.