Model or dataset
RayBytes/ChatMock avatar
RayBytes/ChatMock

ChatMock: a local OpenAI-compatible endpoint built on a signed-in ChatGPT account

OpenAI & Ollama compatible API powered by Codex

1,553 stars216 forksPythonMIT

At a glance

What is it?
ChatMock turns one ChatGPT login into a localhost API that Raycast, terminal agents and other clients can talk to. The interesting parts are the login callback port, the missing client authentication, and the Docker image that does not carry the owner's name.
Who is it for?
Check your OpenAI agreement before anything else: ChatMock republishes a signed-in ChatGPT session over an OpenAI-compatible endpoint, and the project itself states that it is not affiliated with OpenAI and asks you to use it at your own risk. If your agreement permits that and the server stays on your own machine, the parts worth the effort are the discovered model catalog and the reasoning controls, not the desktop wrapper.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 33 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 3, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The terms question comes before the architecture

The short notice at the end of the documentation says to use the project responsibly and at your own risk, and that it is not affiliated with OpenAI. That sentence is the honest summary of what this software is. The repository description calls it an OpenAI and Ollama compatible API powered by Codex, and the tagline says it allows Codex to work in your favourite chat apps and coding tools. In practice you sign in once with a ChatGPT account, the server discovers which models that account can reach, and it republishes them on 127.0.0.1:8000 with an OpenAI-compatible surface.

Nothing in the project changes the terms attached to the account it logs in with. It moves traffic from the first-party client to a process you run, and it hands that process an endpoint any local program can call. That is the whole design, so treat the terms review as the first step rather than an afterthought at the end of a setup guide. The rest of this article sticks to what the repository and its configuration files actually say about how the mechanism is wired.

Login is the mechanism, and it owns port 1455

The getting-started block is two commands, and the first one is the interesting one:

bash
# 1. Sign in with your ChatGPT account
# If you are running this on a headless server, append --headless
chatmock login

# 2. Start the server
chatmock serve

The `--headless` note matters because the login is a browser flow, and a server has no browser. The Docker path makes the same concession explicit. The compose file defines a second service named `chatmock-login`, gated behind `profiles: ["login"]`, whose command is `login` rather than `serve`. That service sets `CHATGPT_LOCAL_LOGIN_BIND=0.0.0.0` and publishes port 1455, which is the OAuth callback port, and it shares the `chatmock_data` volume with the main service so the credentials written during login are visible to the server. The account session is not a token you paste into a config file. It lives in the auth directory named by `CHATGPT_LOCAL_HOME`, which the compose file sets to `/data`, and `.env.example` also carries a commented out OAuth client id next to the warning to modify it only if you know what you are doing.

Nothing authenticates the clients that call port 8000

Read the Terax integration steps closely, because they say the API key may be anything. That is the project's own description of an unauthenticated local server: any client pointed at `http://127.0.0.1:8000/v1` can use the models your account pays for, and nothing distinguishes one local program from another. Raycast is shown being configured through the Ollama settings section with a host URL defaulting to `127.0.0.1:8000`, which is the same endpoint reached through a different compatibility layer.

The compose file decides how far that reaches. Ports are published as `${CHATMOCK_PUBLISH_HOST:-127.0.0.1}:${PORT:-8000}:${PORT:-8000}`, so the safe default binds to loopback only. The same file's `.env.example` then says to use 0.0.0.0 for remote access. Take that literally and you have an unauthenticated bridge from your network to a signed-in ChatGPT session, with credentials sitting in a named Docker volume. Nothing in the configuration adds a token, a password or an allow list on the serving side. If you need other machines to reach it, the protection has to live somewhere other than this project.

The default container image is not published under the owner

The compose file pulls `${CHATMOCK_IMAGE:-storagetime/chatmock:latest}`. The repository owner is RayBytes, the tap is RayBytes/chatmock, and the PyPI project is chatmock, but the container image comes from a Docker Hub namespace named storagetime, and it is pinned to the `latest` tag rather than a digest or a version tag. `.env.example` repeats the same value and lets you override it. Whatever ends up answering on port 8000 is therefore whatever that tag resolves to at the moment you run `docker compose up`, not necessarily the code you just read.

The image is built from `python:3.11-slim`, installs the package with `pip install --no-cache-dir .`, copies an entrypoint from `docker/entrypoint.sh`, and declares `EXPOSE 8000 1455`. The compose healthcheck polls `http://127.0.0.1:{port}/health` every ten seconds with five retries, so a container that comes up but cannot answer that path is reported unhealthy. The install section of the documentation points at a separate DOCKER.md for the Docker instructions, while the compose file and the Dockerfile are where the actual defaults live. If image provenance matters to you, that is the file to read first and the variable to set.

Reasoning is three flags, and one of them rewrites your model list

Three settings decide how thinking is handled. `--reasoning-effort` accepts none, minimal, low, medium, high, xhigh, max and ultra, defaulting to medium. `--reasoning-summary` takes auto, concise, detailed or none. `--reasoning-compat` decides how reasoning comes back to the client, and the flag table lists legacy, o3 and think-tags with think-tags as the default. The comment for the matching environment variable in `.env.example` lists a fourth value, current, that the table never mentions, so the two documents disagree about the same option.

The fourth setting is the one that changes what a client sees. `--expose-reasoning-models` defaults to false; switched on, it lists every reasoning level as its own model, so a client picks a thinking budget by choosing a model name instead of sending a parameter. Two more options are request level rather than server level: the sample payload enables the web search tool with `responses_tools` set to a list containing a web_search type and `responses_tool_choice` set to auto, and another sets `fast_mode` to true on the request. `--enable-web-search` and `--fast-mode` are the server defaults those request fields override.

The catalog is discovered on an hourly clock, not pinned in the repo

The documented catalog is a snapshot of what one account happens to see: `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5`, `gpt-5.4`, `gpt-5.4-mini` and `gpt-5.3-codex-spark`. Discovery is what drives it. `--model-sync` defaults to true and is described as discovering account models automatically, and `--model-refresh-interval` defaults to 3600 seconds, with the environment comment noting that stale data is refreshed without restarting. So the list a client syncs can change underneath it within the hour, and the documentation is careful to call its own list one that the catalog commonly includes.

Two escape hatches sit outside the flag table. `CHATGPT_LOCAL_DEBUG_MODEL` is described in `.env.example` as forcing a specific model name, with `gpt-5.4` as the example. `VERBOSE` turns on request and stream logs. Neither appears in the table of flags that are supposed to go after `chatmock serve`, and `PORT`, `CHATMOCK_PUBLISH_HOST` and `CHATMOCK_IMAGE` are container level settings rather than serve flags, so the instruction that all flags go after serve is narrower than the environment file implies.

Four install routes come from four different places

The install section offers Homebrew, pip or pipx, a graphical build, and Docker. Homebrew goes through a tap the owner publishes:

bash
brew tap RayBytes/chatmock
brew install chatmock
pipx install chatmock

The graphical build is a binary from the releases page for macOS and Windows, which lines up with the optional `gui` extra in `pyproject.toml` pinning Pillow, PyInstaller and PySide6. Docker is deferred to a separate document. Those routes do not share a single publisher, so they do not necessarily give you the same build of the same version.

The Python metadata is strict in one direction and loose in another. `requires-python` is `>=3.11`, with classifiers for 3.11, 3.12 and 3.13, and every runtime dependency is pinned with an exact version, from flask 3.1.1 and websockets 15.0.1 through certifi and urllib3. The version itself is not written down: it is dynamic, read from `chatmock.version.__version__`, while the console script is declared as `chatmock = chatmock.cli:main`. At the repository root, `chatmock.py` sits beside the `chatmock/` package, with `build.py` and `gui.py` outside the package and `tests/` beside them.

Tagged releases stopped before the catalog the README advertises

Three releases are published: v1.2 titled QoL Improvements on 2025-08-22, v1.3 titled GPT-5-Codex Release! on 2025-09-16, and v1.35 titled GPT-5.1 Series, GPT-5.1-Codex-Max on 2025-11-26. The tag sequence jumps from v1.3 to v1.35 without anything in the repository explaining whether that is a decimal slip or a different scheme. More useful is the date gap: the newest tag names the GPT-5.1 series, while the model catalog in the documentation now names gpt-5.6 variants and gpt-5.3-codex-spark. Whatever produces that catalog, it did not come from the 2025-11-26 tag.

The default branch is a different story. The last commit on it is dated 2026-09-01, roughly two months before the catalog above was written, and no release has been cut for any of it. That combination is worth remembering when you decide what to trust: the code keeps moving on main, the last published artifact predates the current model names, and the license file is MIT while the account it logs into is not yours to relicense. Anyone evaluating this should read the code they will actually run rather than the newest tag page.

Editorial conclusion

Check your OpenAI agreement before anything else: ChatMock republishes a signed-in ChatGPT session over an OpenAI-compatible endpoint, and the project itself states that it is not affiliated with OpenAI and asks you to use it at your own risk. If your agreement permits that and the server stays on your own machine, the parts worth the effort are the discovered model catalog and the reasoning controls, not the desktop wrapper. Before you point anything beyond localhost at it, verify two things: that nothing is listening on 0.0.0.0 for port 8000, since the integration notes say the client API key may be anything, and which image tag you actually run, since the compose default is storagetime/chatmock:latest rather than a name under the repository owner. Pin an image you trust and keep the login callback port closed.

Frequently asked questions

Does ChatMock need an OpenAI API key?

No billing key is involved. You sign in with your ChatGPT account through chatmock login, and the Terax integration notes say the API key may be anything when you add an OpenAI Compatible provider.

Which models does ChatMock expose?

It discovers them from the signed-in ChatGPT account rather than shipping a fixed list. The documented catalog commonly includes gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-5.4-mini and gpt-5.3-codex-spark, refreshed on an interval that defaults to 3600 seconds.

Where does ChatMock keep the ChatGPT session?

In the auth directory named by CHATGPT_LOCAL_HOME. The compose file sets it to /data and mounts that path as the chatmock_data named volume, which the separate chatmock-login service shares so the login writes where the server reads.

Can ChatMock sign in on a headless server?

Yes, by appending --headless to chatmock login. The compose file also ships a separate chatmock-login service under the login profile that publishes port 1455 and sets CHATGPT_LOCAL_LOGIN_BIND=0.0.0.0 for the OAuth callback.

What does ChatMock need to run the server itself?

Python 3.11 or newer, since pyproject.toml sets requires-python to >=3.11 and classifies 3.11, 3.12 and 3.13. The container build starts from python:3.11-slim, and the graphical builds for macOS and Windows are downloaded from the releases page.

Official sources

  1. Issues
  2. License: MIT
  3. RayBytes/ChatMock on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/raybytes-chatmock.svg)](https://hysenlabs.com/projects/raybytes-chatmock)