ThinkWatch Core 0.53.0
This release changes what ThinkWatch sends to upstreams. Each upstream now receives the request and only the headers it needs; the client's own identity stays with ThinkWatch unless an upstream asks for it. It also fixes two problems with ChatGPT account upstreams.
Upgrade notes
- The control-plane protocol version is now 26 (it was 25). The request store's schema is unchanged (21). ThinkWatch Lite 2026.9.20 includes 0.52.1 (protocol 25) and does not connect to 0.53.0, so a server used with it stays on 0.52.x until the app is updated to a release that includes 0.53.0.
- Upstreams now see ThinkWatch's
User-Agentinstead of the client's. An upstream that admits only certain clients, such as Kimi For Coding, Bailian Coding Plan or a relay restricted to official clients, needs the new provider fieldforward_client_identity: true. - New message code:
config.credential.chatgpt_client_identity.
Each upstream gets only what it needs. Client request headers used to reach the upstream almost unchanged. Only credentials, a few transport headers and, when a request was translated, the client format's own protocol headers were removed. Claude Code's User-Agent, x-app, x-stainless-* and session ID, Gemini CLI's installation ID and a browser client's Cookie and Origin all went through. Outbound headers now come from three sources only:
- Set by ThinkWatch: its own
User-Agent, andcontent-typewhen the body was translated. - The upstream's configuration: the credential and the headers written there.
OpenAI-OrganizationandOpenAI-Projectbelong here, because they belong to the upstream's key. - The client's request, only for the headers the upstream's protocol uses:
- Anthropic:
anthropic-*, exceptanthropic-dangerous-direct-browser-access. - OpenAI:
Idempotency-KeyandX-Client-Request-Id. - Gemini: none.
- Every protocol:
content-typeandacceptwhen the body passes through unchanged.
- Anthropic:
An Anthropic request without anthropic-version now gets the default one. When the body passes through unchanged, identity fields that clients fill in themselves are removed from it: Claude Code's metadata.user_id, and the Codex installation ID and turn metadata in client_metadata.
forward_client_identity. With this field on, an upstream also receives the client's own User-Agent, x-app, originator, version, session_id and x-codex-* headers, and the body's identity fields are kept. These are the client's own values; nothing is made up. The field is off by default. A ChatGPT account upstream refuses it: that upstream always names ThinkWatch as the sender.
ChatGPT account upstreams.
- New models were missing from the list. The Codex backend leaves a model out of the list when its minimum client version is above the
client_versionthat the caller reports. ThinkWatch reported0.0.0, so a model such as gpt-6-luna, which needs Codex 0.155.0, was not listed, and requests for it were refused with "No upstream serves model …" even though the account can use it. ThinkWatch now reports99999.0.0, so the list shows every model the account can use. Requests still name ThinkWatch as their origin. - The ChatGPT app's identity is no longer forwarded. The Codex inside the ChatGPT desktop app adds an attestation generated by the app (
x-oai-attestation), its installation ID and turn metadata. ThinkWatch forwarded them together with the token it had obtained itself, and on one account OpenAI revoked that token within seconds of the first such request.- From the client, the Codex backend now receives only
x-codex-turn-state,x-openai-internal-codex-responses-liteandx-codex-beta-features. - The attestation, installation ID and turn metadata cannot be set in an upstream's configured headers.
- From the client, the Codex backend now receives only
- Request bodies are compressed. Requests to the Codex backend are compressed with zstd, which is what Codex does when it talks to that backend itself.
Downloads
| Platform | Binary | Archive for server installation |
|---|---|---|
| Linux, x86_64 | twcore-x86_64-unknown-linux-gnu |
twcore-x86_64-unknown-linux-gnu.tar.gz |
| Linux, aarch64 | twcore-aarch64-unknown-linux-gnu |
twcore-aarch64-unknown-linux-gnu.tar.gz |
| macOS, Apple silicon | twcore-aarch64-apple-darwin |
— |
| Windows, x64 | twcore-x86_64-pc-windows-msvc.exe |
— |
| Windows, ARM64 | twcore-aarch64-pc-windows-msvc.exe |
— |
Each file is published with a .sha256 file beside it. A Linux archive contains twcore, the systemd unit twcore.service and LICENSE. ThinkWatch Lite includes its own copy of twcore; the files here are for running core separately, such as on a server.
Server installation
On Linux (x86_64 or aarch64), the install script sets up twcore as a systemd service. This installs 0.53.0:
curl -fsSL https://raw.githubusercontent.com/ThinkWatchProject/ThinkWatch-Core/main/scripts/install.sh | sudo sh -s -- --version 0.53.0An installation made with the script switches to 0.53.0 with:
sudo twcore upgrade --version 0.53.0 --restartConfiguration, the remote control port and connecting ThinkWatch Lite are described in docs/server.md.
Verifying a download
A .sha256 file holds the SHA-256 of the file followed by its name. With both files in the current directory, on Linux:
sha256sum -c twcore-x86_64-unknown-linux-gnu.tar.gz.sha256On macOS:
shasum -a 256 -c twcore-aarch64-apple-darwin.sha256On Windows, in PowerShell, the following prints True when the binary matches:
(Get-FileHash .\twcore-x86_64-pc-windows-msvc.exe).Hash -eq (Get-Content .\twcore-x86_64-pc-windows-msvc.exe.sha256).Split()[0]The install script and twcore upgrade check the SHA-256 themselves.
What's Changed
- fix(gateway): list every model a ChatGPT account can use; stop forwarding the ChatGPT app's identity by @fylorn in #217
- feat(gateway): send each upstream only what it needs by @fylorn in #218
- chore: v0.53.0 by @fylorn in #219
Full Changelog: v0.52.1...v0.53.0