v0.5.0
A codex subscription can now be a rung in the waterfall. It is a full
participant -- tool calls work -- so it can sit anywhere in the chain rather
than only at the bottom.
Codex subscription as a waterfall rung (#35)
Every other rung is an api_key HTTP row that LiteLLM dials from config alone.
A codex subscription is not: it authenticates with the ChatGPT OAuth tokens
the codex CLI keeps in ~/.codex/auth.json, and it speaks the Responses API
rather than chat/completions. shmobster/codex_llm.py bridges that as an
in-process litellm.CustomLLM -- there is no second process to run under
launchd.
One keyless row enables it:
{"name": "codex", "model": "codex/chatgpt/gpt-5.5"}
The chatgpt/ segment is load-bearing, not decoration. LiteLLM dispatches on
the model name before it dispatches on the custom provider, so a row of
codex/gpt-5.5 leaves it holding the bare gpt-5.5, recognising that as an
OpenAI model, and quietly billing a platform API key -- the bridge is never
reached, and if OPENAI_API_KEY happens to be valid there is no error at all.
The segment is stripped back off before the request goes out. Written up
generically as
skillz#181.
Two more things the live endpoint dictates, neither of them documented:
stream: trueis mandatory. A non-streaming request is refused outright
with400 Stream must be set to true, so the SSE body is read whole and parsed
even though nothing downstream streams.- The model must be one your ChatGPT plan allows.
gpt-5.5works;
gpt-5.1-codexis refused with "not supported when using Codex with a ChatGPT
account".
Why read codex's token instead of driving the binary. The alternatives were
codex exec or the codex app-server JSON-RPC that OpenClaw's codex extension
speaks. Both keep the token out of our hands, but both hand us an agent: codex
brings its own tool set, sandbox and approval policy, and shmobster already owns
that loop (handler + YOLT gate + channel policy). Nesting a second agent inside
one waterfall rung buys nothing here, and codex exec additionally returns final
text only -- no tool calls.
Token rotation stays yours. auth.json is re-read on every call, so any
rotation the codex CLI performs is picked up without a restart. shmobster
deliberately does not refresh it: that would mean writing back to auth.json
and racing the CLI over a refresh token that may be single-use, and breaking your
actual codex login is worse than one dead rung. Instead the token's own exp is
read per call:
codex: the ChatGPT token expires in ~19h; run `codex login` to rotate it
logged at most hourly so a busy channel does not turn it into spam. Once expired
the rung returns 401, LiteLLM cools it, and the chain falls through. Either way
the fix is codex login -- or just using the codex CLI for anything, which
rotates the file as a side effect.
Upgrading
git pull
.venv/bin/pip install -r requirements.txt
.venv/bin/python selfcheck.py
deploy/service.sh restart
- Nothing is required. No new dependency, and no config change unless you
want the codex rung. - To enable it, add the keyless row above to your
waterfall. It needs a
codex login on that machine (codex login);CODEX_HOMEis honoured if you
set it. Verify withcodex login statusbefore restarting. - If you add the row, do not shorten the model string.
codex/gpt-5.5
without thechatgpt/segment silently routes to OpenAI on your platform key
instead of your subscription -- see above. - Keyless rows are now supported generally. A waterfall entry may omit
api_keyentirely; previously an absent key was still passed through as empty.
Existing rows are unaffected.