# codex-app-transfer tested two providers end to end, and said so

> This is a local desktop gateway, written in Rust with a Tauri shell, that sits between a coding assistant and whichever inference provider you want, translating one request format into six. What makes it worth reading is not the translation but the engineering around it: a patch-repair layer that fixes malformed edit requests from a whitelist and refuses to guess on anything it does not recognise, and a test-coverage notice at the top of the readme that names the two providers with real end-to-end testing out of more than a dozen built in.

**Cmochance/codex-app-transfer** — Local desktop gateway that translates OpenAI Codex CLI's Responses API into Chat Completions for Kimi / DeepSeek / Zhipu GLM / Bailian and other OpenAI-compatible providers.

- Repository: https://github.com/Cmochance/codex-app-transfer
- Stars: 304 · Forks: 31
- Language: Rust
- License: MIT
- Published: 2026-09-15 · Updated: 2026-09-15 · Language: en
- Canonical page: https://hysenlabs.com/projects/cmochance-codex-app-transfer

## Two providers tested, a dozen listed as unit tests only

The very first thing in the readme is a notice about test coverage, and it is the most useful paragraph in the repository. The project states that end-to-end testing against real services has been completed for exactly two providers: a coding-oriented plan from one vendor and a token-plan tier from another. Then it names the ones that have not: a long list including several competing plans and login styles from the same vendor families, two regional model hosts, an international cloud platform in two billing modes, a domestic vendor with both an API key and a token plan, and three workplace-branded clients. Those are described as having no long-term regression testing, resting on unit tests plus occasional user feedback. The same paragraph then asks for API keys to test the others, gives a contact route, and promises the keys will only be used for testing. Publishing that inventory in the header is rarer than publishing a benchmark, and it tells you exactly which entries on the provider list you should avoid.

## The readme names a version that is not the newest tag

The readme states a current version of two point four point five and points to the changelog and the releases page for detail. The release history shows the three most recent tags as two point four point four, two point four point three and two point four point two, published in early July of 2026, with the patch-level tag being the newest of the three. So the version the readme advertises is one ahead of anything tagged. That can be entirely innocent: a build cut and uploaded without a tag, or a changelog entry written ahead of the tag push. What makes it worth noting is the other date. The repository was pushed to at the end of September 2026, roughly three months after the newest tag, so the default branch is well ahead of every release. If you are reading release notes to work out what changed, read the changelog in the documents directory rather than inferring from a tag, and pin a tag rather than a branch if you need something reproducible.

## One fixed loopback port, and the window is not the exit

The mechanism is simple and worth being precise about. The tool starts a gateway on the local machine; once forwarding is enabled, the coding client talks to it over a single hardcoded loopback address and port. The desktop application manages providers, the mapping from model names to real provider identifiers, the forwarding port, and a log panel, so the whole configuration surface is four things. The behaviour that will surprise you is the lifecycle. Closing the window does not stop the tool; it shrinks to the system tray and keeps serving requests, and only quitting from the tray context menu ends it. For a local proxy that is the correct default, since a stray window close mid-session should not sever your conversation, but it also means the process outlives the interface you think you closed. If you are auditing what is running on a machine, look for the tray icon and the listening port rather than for a window.

## Six upstream protocols behind one conversion layer

The conversion list is longer than the name of the project suggests. On the request side the tool translates the client's streaming and non-streaming requests into plain chat completions, into a native Gemini streaming endpoint, into a Gemini command-line authorisation flow, into an Anthropic messages endpoint, into a specific web chat endpoint used by one provider, and it also supports passing the original format straight through. On the naming side it maps the client's expected model names onto whatever the provider actually calls those models, with five names enumerated for the OpenAI-shaped models. Two things follow. The abstraction is not a single translation but a set of adapters, and the adapters are where all the per-provider work lives: the reasoning-channel fix, the patch bridging, the image generation interception and the error translation are each described as applying to particular protocols rather than to all of them.

## The patch repair layer fixes what it knows and refuses the rest

This is the best-engineered thing in the project. Third-party chat models are not bound by the syntax constraints the first-party models get, so they produce malformed edit requests in a documented patch format: doubled section markers, missing line prefixes on new files, context that does not match the bytes on disk, a missing begin and end envelope, missing blank lines, and several non-contiguous edits with no separator between them. The repair layer reads the file from disk, realigns the section anchors and context against the actual bytes, inserts the missing separators by splitting hunks at the file's real positions, and converts empty files and empty renames into a delete plus an add. Then three constraints, and they are what make it safe. It is non-destructive: nothing is dropped and nothing is overwritten. It only acts on a whitelist. And anything it does not recognise is passed through untouched, with the stated reasoning that the client will report the error and the model will correct itself, rather than the tool guessing. There is a documented exception where it does act on an unrecognised shape: an end marker with a stray line prefix, which it disambiguates by file type, stripping it for code and structured configuration and leaving it for documents rather than risk deleting body text.

## Reasoning moved from two channels to one after it flickered

The changelog-style notes in the feature list are the most informative part of the readme, because they record decisions being reversed. The first implementation sent the reasoning stream on two channels at once, a summary channel and a content channel, for compatibility with an earlier client behaviour. Testing showed the cost: the same reasoning block updated twice and the whole passage flickered during streaming. The decision was to converge back to the single summary channel. Two adjacent fixes came out of the same investigation, one closing the reasoning stream before a tool call opens so the two event types stop interleaving, and one stopping an empty text part after a function call from generating a phantom empty message on the Gemini path, so a turn's tool calls fold together as they should. Two error codes are attached to that work, which is a small courtesy that makes a changelog searchable.

## Process collapsing works by delaying one event

The feature list describes the closest thing here to replicating a first-party behaviour: after a turn finishes, the reasoning, the tool calls and the setup messages collapse into a single worked-for line and only the final reply stays expanded. The implementation is a timing trick and it is worth reading as such. A top-level phase field is added to assistant message items, marking tool-turn setup as commentary and the final reply as the answer. During streaming, every new output item is emitted first as temporary commentary, and the completion event for a message is deliberately delayed until the tail of the stream, where the stop reason and the seen-tool-calls flag are known, so the authoritative phase is emitted exactly once and does not flicker mid-turn. Three conversion paths get this treatment; the web chat path and the direct passthrough do not, because they are not converted. And there is an honest caveat: the final reply appears in the process area while streaming and is promoted at the end, because a third-party model cannot declare its message channel in advance the way the first-party one does.

## The workspace is eleven crates and a build tool, with two planned

The build configuration describes a deliberately decomposed workspace. Eleven members are active: an HTTP crate, the Tauri application, a registry, a proxy, an adapters crate, a codex-integration crate, a conversation-export crate, and two crates named for a single provider each, one for a Gemini authorisation flow and one for another vendor's authentication. Plus a workspace build tool. Two further members are present but commented out with a note that they will be enabled in later phases. So a project that presents as one desktop app is really a proxy core with per-provider concerns split into their own crates, which is the right shape if the provider list is going to keep growing. The local make file then does almost nothing: one target builds an unsigned macOS application bundle for self-testing, and one cleans build directories. Releases for all three platforms go through a hosted workflow instead, triggered either by dispatching it with a version argument or by pushing a tag.

## Conclusion

This gateway fits someone committed to a desktop coding client who needs it to talk to a provider the client does not natively support, and who can verify the specific provider they care about rather than trusting a list. It does not fit anyone who needs the whole provider list to work, because the readme states plainly that only two have been tested against real hardware and the rest have unit tests and occasional user reports. Before you rely on it, check whether your provider is one of the tested two and treat the others as unverified, watch the tray icon rather than the window, because closing the window leaves it forwarding, and expect the patch repair layer to pass malformed edits through rather than guess, which is the right failure mode but will surface as model-side errors you have to read.

## FAQ

### Which providers has codex-app-transfer actually tested?

The readme states that end-to-end testing against real services is complete for two providers only, a coding plan from one vendor and a token-plan tier from another. More than a dozen other built-in providers, including several login and billing styles, are listed as having only unit tests and occasional user feedback, with no long-term regression testing.

### What does the codex-app-transfer gateway do?

It runs a local gateway that the desktop coding client talks to over a fixed loopback address and port, and translates the requests the client sends into whichever upstream protocol the chosen provider speaks. A desktop interface manages the providers, the mapping from model names to real provider identifiers, the port and the logs.

### Which upstream API formats can codex-app-transfer convert to?

The conversion layer handles chat completions, a native Gemini streaming endpoint, a Gemini command-line authorisation flow, an Anthropic messages endpoint, a provider-specific web chat endpoint, and a straight passthrough of the original format. Not every feature applies to every path, which is why the feature notes name the conversion path each fix touches.

### What happens to a malformed file-edit request from a third-party model?

A middle layer repairs a whitelisted set of format problems by reading the file from disk and realigning section markers and context to the real bytes, without dropping content or overwriting anything. Anything it does not recognise is passed through untouched so the client reports the error and the model self-corrects, with one file-type-specific exception for a stray prefix on the end marker.

### Does closing the codex-app-transfer window stop it?

No. Closing the window shrinks the application to the system tray and it keeps forwarding requests; only quitting from the tray menu ends it. The readme describes this as the intended behaviour so that a stray window close does not interrupt a conversation.

## Sources

- [Cmochance/codex-app-transfer on GitHub](https://github.com/Cmochance/codex-app-transfer)
- [Issues](https://github.com/Cmochance/codex-app-transfer/issues)
- [License: MIT](https://github.com/Cmochance/codex-app-transfer/blob/main/LICENSE)
- [README](https://github.com/Cmochance/codex-app-transfer/blob/main/README.md)
- [Releases](https://github.com/Cmochance/codex-app-transfer/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/cmochance-codex-app-transfer
