OpenAI Codex (cloud) Elixir support

does any one was able to run mix test with codex.

Yes, installing hex is working with mix archive.install github hexpm/hex branch latest --force, it’s rebar that’s giving me troubles.

Installing deps from github is working, but installing deps from hex.pm or cdn.jsdelivr.net is not. I guess they have to whitelist these domains first.

Hey all, just checking in, is codex working okay for you at this point? Have you found any gotchas? I originally tried to use the hex mirror and found some dependencies didn’t work. Has this been your experience?

I would really like to use it if possible!

1 Like

I ended up going back to the (locally used) Claude Code. The hex mirror is too unstable, and while the codex’s promise is good, I will wait till they improve their infrastructure.

Ahh, okay thanks for the update. I hope it’s working soon.

I’m using the gist posted in this thread and it does work - sometimes. When it fails, I restart the task. Sometimes it takes a few restarts before it succeeds. But it does succeed eventually.

Annoying, but codex is free for now so I’d rather use it than other options.

3 Likes

Sometimes it takes a few restarts before it succeeds.

Honestly, I feel like it’s worse than before? I just restarted a task five times last night, three times now… Without success.

I don’t know if the problem is on OpenAI’s side or Hex’s, but it’s really frustrating. Especially when you see the boost that Codex represents on non-Elixir projects…

Curious, has anyone tried hosting their own private mirror of hex? Wondering if that’s a viable option.

Can you show the 403 errors. Afaict we don’t respond with 403 errors from repo.hex.pm unless you are doing authenticated requests for private packages.

I have tried the script provided by @vkryukov but I get the same error when using jsDeliver and no mirror. Can someone show the errors they are getting when using repo.hex.pm directly?

1 Like

I asked our engineer Savvas to look into this. He is still working on it and will post more details later. But here the brief explanation of what is broken and how to work around it.

Here is the setup script that should work for now:

# OpenAI Codex setup script for Elixir projects
go install github.com/asdf-vm/asdf/cmd/asdf@v0.18.0
asdf plugin add erlang https://github.com/michallepicki/asdf-erlang-prebuilt-ubuntu-24.04.git || true
asdf plugin add elixir
asdf install erlang 28.0.2
asdf set --home erlang 28.0.2
asdf install elixir 1.18.4-otp-28
asdf set --home elixir 1.18.4-otp-28
echo 'export PATH=$HOME/.asdf/shims:$PATH' >> ~/.bashrc
echo 'export HEX_CACERTS_PATH=$CODEX_PROXY_CERT' >> ~/.bashrc
export PATH=$HOME/.asdf/shims:$PATH
export HEX_CACERTS_PATH=$CODEX_PROXY_CERT
# use hex fork with a workaround for httpc bug https://github.com/erlang/otp/issues/10065
mix archive.install --force github 650health/hex branch latest
# mix local.rebar doesn't work on Codex likely because it's not respecting HEX_CACERTS_PATH env var.
# TODO investigate this further
# install rebar manually as a temporary workaround
curl -L -o rebar3 https://s3.amazonaws.com/rebar3/rebar3
chmod +x ./rebar3
./rebar3 local install
export PATH=/root/.cache/rebar3/bin:$PATH
mix local.rebar rebar3 $(which rebar3)

mix deps.get
mix deps.compile
mix compile
4 Likes

Since mise is already used in codex and it supports asdf plugins it can be used instead

# make sure mise + its shims are on PATH now and later
echo 'export PATH=$HOME/.local/bin:$PATH' >> ~/.bashrc
echo 'export PATH=$HOME/.local/share/mise/shims:$PATH' >> ~/.bashrc
echo 'export HEX_CACERTS_PATH=$CODEX_PROXY_CERT' >> ~/.bashrc
export PATH=$HOME/.local/bin:$PATH
export PATH=$HOME/.local/share/mise/shims:$PATH
export HEX_CACERTS_PATH=$CODEX_PROXY_CERT

# plugins (mise can use asdf-style plugins)
mise plugins install erlang https://github.com/michallepicki/asdf-erlang-prebuilt-ubuntu-24.04.git || true
mise plugins install elixir https://github.com/mise-plugins/mise-elixir.git

# tool installs + set as global (equivalent to asdf --home)
mise install erlang@28.0.2
mise use --global erlang@28.0.2
mise install elixir@1.18.4-otp-28
mise use --global elixir@1.18.4-otp-28

# use hex fork with a workaround for httpc bug https://github.com/erlang/otp/issues/10065
mix archive.install --force github 650health/hex branch latest

# mix local.rebar doesn't work on Codex likely because it's not respecting HEX_CACERTS_PATH env var.
# TODO investigate this further
# install rebar manually as a temporary workaround
curl -L -o rebar3 https://s3.amazonaws.com/rebar3/rebar3
chmod +x ./rebar3
./rebar3 local install
export PATH=/root/.cache/rebar3/bin:$PATH
mix local.rebar rebar3 "$(which rebar3)"

mix deps.get
mix compile
2 Likes

I struggled a bit to get a Phoenix + Ash project running tests inside OpenAI’s Codex environment, but I found a setup that works reliably. Several steps run in parallel to keep it fast.

Gist: elixir-phoenix-ash-codex-setup.sh Ā· GitHub
Pay attention: You will need to change "app_dev"

I’ll be really happy to improve it based on your feedback

1 Like

Has anyone successfully used codex with rustler?

For example, I’m using mdex and am having issues with the http proxy reaching out to github. I think I could precompile the dependencies though I’d prefer not to change my application configuration just for codex.

I’ve verified the same issue with other rustler dependencies as well.

==> mdex
Compiling 3 files (.ex)
12:29:02.476 [debug] Downloading NIF from https://github.com/leandrocp/mdex/releases/download/v0.1.14/libcomrak_nif-v0.1.14-nif-2.15-x86_64-unknown-linux-gnu.so.tar.gz
12:29:02.476 [debug] Using HTTP_PROXY: http://proxy:8080
12:29:02.476 [debug] Using HTTPS_PROXY: http://proxy:8080
12:29:02.617 [info] Attempt 1 failed with {:error, "couldn't fetch NIF from https://github.com/leandrocp/mdex/releases/download/v0.1.14/libcomrak_nif-v0.1.14-nif-2.15-x86_64-unknown-linux-gnu.so.tar.gz: {:ok, {{~c\"HTTP/1.1\", 503, ~c\"Service Unavailable\"}, [{~c\"date\", ~c\"Mon, 08 Sep 2025 12:29:02 GMT\"}, {~c\"server\", ~c\"envoy\"}, {~c\"content-length\", ~c\"85\"}, {~c\"content-type\", ~c\"text/plain\"}], \"upstream connect error or disconnect/reset before headers. reset reason: remote reset\"}}"}
12:29:04.558 [debug] Downloading NIF from https://github.com/leandrocp/mdex/releases/download/v0.1.14/libcomrak_nif-v0.1.14-nif-2.15-x86_64-unknown-linux-gnu.so.tar.gz
12:29:04.558 [debug] Using HTTP_PROXY: http://proxy:8080
12:29:04.558 [debug] Using HTTPS_PROXY: http://proxy:8080
12:29:04.693 [info] Attempt 2 failed with {:error, "couldn't fetch NIF from https://github.com/leandrocp/mdex/releases/download/v0.1.14/libcomrak_nif-v0.1.14-nif-2.15-x86_64-unknown-linux-gnu.so.tar.gz: {:ok, {{~c\"HTTP/1.1\", 503, ~c\"Service Unavailable\"}, [{~c\"date\", ~c\"Mon, 08 Sep 2025 12:29:04 GMT\"}, {~c\"server\", ~c\"envoy\"}, {~c\"content-length\", ~c\"85\"}, {~c\"content-type\", ~c\"text/plain\"}], \"upstream connect error or disconnect/reset before headers. reset reason: remote reset\"}}"}
12:29:07.951 [debug] Downloading NIF from https://github.com/leandrocp/mdex/releases/download/v0.1.14/libcomrak_nif-v0.1.14-nif-2.15-x86_64-unknown-linux-gnu.so.tar.gz
12:29:07.951 [debug] Using HTTP_PROXY: http://proxy:8080
12:29:07.951 [debug] Using HTTPS_PROXY: http://proxy:8080
12:29:08.030 [info] Attempt 3 failed with {:error, "couldn't fetch NIF from https://github.com/leandrocp/mdex/releases/download/v0.1.14/libcomrak_nif-v0.1.14-nif-2.15-x86_64-unknown-linux-gnu.so.tar.gz: {:ok, {{~c\"HTTP/1.1\", 503, ~c\"Service Unavailable\"}, [{~c\"date\", ~c\"Mon, 08 Sep 2025 12:29:07 GMT\"}, {~c\"server\", ~c\"envoy\"}, {~c\"content-length\", ~c\"85\"}, {~c\"content-type\", ~c\"text/plain\"}], \"upstream connect error or disconnect/reset before headers. reset reason: remote reset\"}}"}
Compiling lib/mdex/native.ex (it's taking more than 10s)
12:29:12.743 [debug] Downloading NIF from https://github.com/leandrocp/mdex/releases/download/v0.1.14/libcomrak_nif-v0.1.14-nif-2.15-x86_64-unknown-linux-gnu.so.tar.gz
12:29:12.743 [debug] Using HTTP_PROXY: http://proxy:8080
12:29:12.743 [debug] Using HTTPS_PROXY: http://proxy:8080
== Compilation error in file lib/mdex/native.ex ==
** (RuntimeError) Error while downloading precompiled NIF: couldn't fetch NIF from https://github.com/leandrocp/mdex/releases/download/v0.1.14/libcomrak_nif-v0.1.14-nif-2.15-x86_64-unknown-linux-gnu.so.tar.gz: {:ok, {{~c"HTTP/1.1", 503, ~c"Service Unavailable"}, [{~c"date", ~c"Mon, 08 Sep 2025 12:29:12 GMT"}, {~c"server", ~c"envoy"}, {~c"content-length", ~c"85"}, {~c"content-type", ~c"text/plain"}], "upstream connect error or disconnect/reset before headers. reset reason: remote reset"}}.
You can force the project to build from scratch with:
config :rustler_precompiled, :force_build, mdex: true
In order to force the build, you also need to add Rustler as a dependency in your `mix.exs`:
{:rustler, ">= 0.0.0", optional: true}
lib/mdex/native.ex:9: (module)
could not compile dependency :mdex, "mix compile" failed. Errors may have been logged above. You can recompile this dependency with "mix deps.compile mdex --force", update it with "mix deps.update mdex" or clean it with "mix deps.clean mdex"

Does it work without a proxy? Is the proxy a hard requirement?

AFAIK it’s a requirement. All traffic runs through the proxy for security reasons:

Environments run behind an HTTP/HTTPS network proxy for security and abuse prevention purposes. All outbound internet traffic passes through this proxy.

Cloud environments (source)

For more context, this is an issue during the ā€œinstall dependencyā€ phase where internet access is enabled by default.

I see. Well, HTTP 503 can mean anything really, I’ve seen it used in cases where it was actually HTTP 400. No idea, sorry. Don’t have enough context.

I had the following in my setup script from a combination of several answers, which make the agent seemingly running tests and formatting.

install -Dm644 "$CODEX_PROXY_CERT" /usr/local/share/ca-certificates/codex-proxy.crt
update-ca-certificates

echo 'export ERL_SSL_CACERTFILE=/etc/ssl/certs/ca-certificates.crt' >> ~/.bashrc
echo 'export HEX_CACERTS_PATH=/etc/ssl/certs/ca-certificates.crt' >> ~/.bashrc

export ERL_SSL_CACERTFILE=/etc/ssl/certs/ca-certificates.crt
export HEX_CACERTS_PATH=/etc/ssl/certs/ca-certificates.crt

# Downloading patched hex
mix archive.install --force github 650health/hex branch latest

# Install rebar3 manually.
curl -L -o rebar3 https://s3.amazonaws.com/rebar3/rebar3
chmod +x ./rebar3
./rebar3 local install
export PATH=/root/.cache/rebar3/bin:$PATH
mix local.rebar rebar3 $(which rebar3)

mix deps.get

And just the following in my maintenance script.

mix deps.get

I had to enable full internet access though, as it seems that some dependencies were still fetched after the setup step.

The underlying bug has been fixed in OTP and Elixir will work in Codex Cloud with the latest Erlang patches.

We patched erlang/otp httpc module. It has been released in OTP 28.1, 27.3.4.3 and 26.2.5.15. mix deps.get now works as expected since httpc no longer sends the te header for default GET requests.

Thanks @Damirados for the sample using Mise en Place. This works:

# make sure mise + its shims are on PATH now and later
echo 'export PATH=$HOME/.local/bin:$PATH' >> ~/.bashrc
echo 'export PATH=$HOME/.local/share/mise/shims:$PATH' >> ~/.bashrc
echo 'export HEX_CACERTS_PATH=$CODEX_PROXY_CERT' >> ~/.bashrc
export PATH=$HOME/.local/bin:$PATH
export PATH=$HOME/.local/share/mise/shims:$PATH
export HEX_CACERTS_PATH=$CODEX_PROXY_CERT

mise use --global erlang@28.1
mise use --global elixir@1.18.4-otp-28

mix deps.get
mix deps.compile
mix compile
5 Likes

I am still not able to compile, this time due to Cldr it seems.


== Compilation error in file lib/professional_profiles/cldr.ex ==
** (CaseClauseError) no case clause matching: {:error, {:failed_connect, [{:to_address, {~c"raw.githubusercontent.com", 443}}, {:tls, [verify: :verify_peer, cacertfile: ~c"/workspace/app-professional-profiles/_build/test/lib/castore/priv/cacerts.pem", depth: 4, ciphers: [%{prf: :sha256, mac: :aead, cipher: :aes_128_gcm, key_exchange: :any}, %{prf: :sha384, mac: :aead, cipher: :aes_256_gcm, key_exchange: :any}, %{prf: :sha256, mac: :aead, cipher: :chacha20_poly1305, key_exchange: :any}, %{prf: :sha256, mac: :aead, cipher: :aes_128_gcm, key_exchange: :ecdhe_ecdsa}, %{prf: :sha256, mac: :aead, cipher: :aes_128_gcm, key_exchange: :ecdhe_rsa}, %{prf: :sha384, mac: :aead, cipher: :aes_256_gcm, key_exchange: :ecdh_ecdsa}, %{prf: :sha384, mac: :aead, cipher: :aes_256_gcm, key_exchange: :ecdh_rsa}, %{prf: :sha256, mac: :aead, cipher: :chacha20_poly1305, key_exchange: :ecdhe_ecdsa}, %{prf: :sha256, mac: :aead, cipher: :chacha20_poly1305, key_exchange: :ecdhe_rsa}, %{prf: :sha256, mac: :aead, cipher: :aes_128_gcm, key_exchange: :dhe_rsa}, %{prf: :sha384, mac: :aead, cipher: :aes_256_gcm, key_exchange: :dhe_rsa}], versions: [:"tlsv1.2", :"tlsv1.3"], eccs: [:secp384r1, :secp256r1], reuse_sessions: true, server_name_indication: ~c"raw.githubusercontent.com", secure_renegotiate: true, customize_hostname_check: [match_fun: #Function<6.112534691/2 in :public_key.pkix_verify_hostname_match_fun/1>]], {:tls_alert, {:unknown_ca, ~c"TLS client: In state wait_cert_cr at ssl_handshake.erl:2183 generated CLIENT ALERT: Fatal - Unknown CA\n"}}}]}}
(cldr_utils 2.28.3) lib/cldr/http/http.ex:281: Cldr.Http.get_with_headers/2
(cldr_utils 2.28.3) lib/cldr/http/http.ex:120: Cldr.Http.get/2
(ex_cldr 2.43.1) lib/cldr/install.ex:104: Cldr.Install.do_install_locale_name/3
(elixir 1.18.4) lib/enum.ex:987: Enum."-each/2-lists^foreach/1-0-"/2
(ex_cldr 2.43.1) lib/cldr/install.ex:29: Cldr.Install.install_known_locale_names/1
(ex_cldr 2.43.1) lib/cldr.ex:102: Cldr.install_locales/1
(ex_cldr 2.43.1) expanding macro: Cldr.Backend.Compiler.__before_compile__/1
lib/professional_profiles/cldr.ex:1: ProfessionalProfiles.Cldr (module)

This is my ā€setupā€

cd /workspace/app-professional-profiles

mise install

echo 'export PATH=$HOME/.local/bin:$PATH' >> ~/.bashrc
echo 'export PATH=$HOME/.local/share/mise/shims:$PATH' >> ~/.bashrc
echo 'export HEX_CACERTS_PATH=$CODEX_PROXY_CERT' >> ~/.bashrc
export PATH=$HOME/.local/bin:$PATH
export PATH=$HOME/.local/share/mise/shims:$PATH
export HEX_CACERTS_PATH=$CODEX_PROXY_CERT

# Activate mise for the current session
eval "$(mise activate -q bash)"

mix local.hex --force

mix deps.get

mix test

ex_cldr uses Erlang’s :httpc module to download configured locales at compile time. The error seems to be CLIENT ALERT: Fatal - Unknown CA which is a surprise to me - I’m not even sure which CA is in effect at the time you are compiling (and I am far from knowledgable about CAs). I’ve fixed the case clause error on the development branch but that doesn’t resolve the underlying error.

Ultimately it is Cldr.Http.get/2 that does the work and it has two options you might try to see if you can at least get around the error for now:

  1. Set the env variable CLDR_UNSAFE_HTTPS=true (not recommended for production)
  2. Configure (in config.exs since it’s required for compile time) a different certificate store and see if that connects as expected. The error message indicates you have castore configured and it’s using that libraries certificate store - which is very common. Maybe you can see if there is a later version than what you have installed? There was a new version on August 12th.
  3. You can test by doing:
iex> `Cldr.Http.get("Cldr.Http.get("https://raw.githubusercontent.com/elixir-cldr/cldr/refs/tags/v2.43.2/priv/cldr/locales/en.json")")` 

These options are discussed in the documentation but added here to make it hopefully easier for you to access:

Unsafe HTTPS

If the environment variable CLDR_UNSAFE_HTTPS is
set to anything other than FALSE, false, nil
or NIL then no peer verification of certificates
is performed. Setting this variable is not recommended
but it may be required where peer verification fails for
unidentified reasons. Please open an issue
if this occurs.

Certificate stores

In order to keep dependencies to a minimum,
get/1 attempts to locate an already installed
certificate store. It will try to locate a
store in the following order which is intended
to satisfy most host systems. The certificate
store is expected to be a path name on the
host system.

# A certificate store configured by the
# developer
Application.get_env(:ex_cldr, :cacertfile)

# Populated if hex package `CAStore` is configured
CAStore.file_path()

# Populated if hex package `certfi` is configured
:certifi.cacertfile()

# Debian/Ubuntu/Gentoo etc.
"/etc/ssl/certs/ca-certificates.crt",

# Fedora/RHEL 6
"/etc/pki/tls/certs/ca-bundle.crt",

# OpenSUSE
"/etc/ssl/ca-bundle.pem",

# OpenELEC
"/etc/pki/tls/cacert.pem",

# CentOS/RHEL 7
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",

# Open SSL on MacOS
"/usr/local/etc/openssl/cert.pem",

# MacOS & Alpine Linux
"/etc/ssl/cert.pem"
3 Likes