# moon-bridge: one OpenAI Responses endpoint in front of four upstream protocols

> Moon Bridge is a Go proxy that exposes the OpenAI Responses API on port 38440 and translates requests to Anthropic Messages, Google Gemini or OpenAI Chat Completions upstream, choosing the provider from a model alias. It is aimed at teams that want a single local endpoint for CLI tools such as Codex CLI and Claude Code.

**ZhiYi-R/moon-bridge** — Moon Bridge 是一个用 Go 编写的协议转换与模型路由代理。对外暴露 OpenAI Responses API（/v1/responses），对内支持 Anthropic Messages、Google Gemini（GenAI）、OpenAI Chat Completions 等多种上游协议。客户端指定不同模型别名时，自动将请求路由到对应上游 Provider 并在协议间自动转换。

- Repository: https://github.com/ZhiYi-R/moon-bridge
- Stars: 757 · Forks: 126
- Language: Go
- License: GPL-3.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/zhiyi-r-moon-bridge

## The proxy speaks one inbound dialect and four upstream ones

Moon Bridge is a Go program that sits between a client and one or more model providers. On the client side it presents the OpenAI Responses API, with the main entry point at /v1/responses and a second path without the /v1 prefix. On the provider side it understands four upstream protocols: Anthropic Messages, Google Gemini through its GenAI interface, and OpenAI Chat Completions.

That asymmetry is the point of the design. A client that only knows how to speak one dialect can be pointed at any of those upstreams, and the client never learns which one actually answered. The README describes the flow in a single line: a client names a model alias, the alias selects a provider, the request is translated into that provider's protocol, and the answer is translated back.

The runtime surface is small and HTTP oriented. Besides /v1/responses there is /v1/models to list what is available, and /console/ which serves an embedded web console for configuration. A management API lives under /api/v1/ and, according to the README, only exists when persistence has been enabled.

The practical audience is a developer running local coding agents. Instead of editing a tool's provider settings every time a model moves, you point the tool at one address and edit the routing table in a YAML file.

## Routes map a model alias onto a provider and an upstream model name

Routing is configuration, not code. The configuration file is YAML and its core structure has three parts: models, providers and routes. The routes section is the interesting one, because it maps the model alias a client asks for onto the upstream model name of a specific provider.

That indirection buys two things. First, the client configuration stays stable: Codex CLI or Claude Code keeps asking for the same alias even when the alias now points somewhere else. Second, several aliases can point at different providers, so one tool call can reach a different backend depending on the alias name.

The repository ships a config.example.yml at the top level, and the README points to docs/CONFIGURATION.md for the full reference, including the management API described in docs/api.md. There is also a command line switch, -dump-config-schema, which writes a config.schema.json file describing the accepted structure. That is the fastest way to understand the schema for a given build without reading Go source, and it also means editors can validate the file.

A detail worth knowing: the default config path is $HOME/moonbridge/config.yml, and the -config flag overrides it. The first run with no configuration creates that file, so a fresh start and a configured start take different paths.

## Transform is one of three run modes, and the other two do not convert

The -mode flag selects one of three behaviours, and the difference matters when you debug a request that comes back wrong.

In Transform mode, which the README marks as the default, the proxy accepts an OpenAI Responses request, converts it to the upstream protocol, forwards it, and converts the response back before returning it to the client. This is the full translation path described above.

CaptureAnthropic is a transparent path: it accepts Anthropic Messages requests and forwards them to an Anthropic upstream without conversion. CaptureResponse does the same for the OpenAI Responses protocol against an OpenAI upstream. The word capture is doing useful work in those names. These modes exist to observe and route traffic, and to give the trace facility a clean path through the proxy, but they deliberately do not translate.

The mode can come from the configuration file or be forced on the command line with -mode, and there are two diagnostic switches that only print and exit: -print-mode prints the effective mode and -print-addr prints the effective listen address. Combined with -print-default-model and -print-codex-model, which print the default alias and the Codex model, you can check what the running configuration resolves to without starting the server at all.

## Plugins, tracing and usage stats sit around the conversion path

Beyond conversion and routing, the README lists a set of features that wrap the request path. The extension point is a CorePluginHooks interface, and the hooks cover request preprocessing, response postprocessing and stream interception. The repository has an extensions/ directory, and the Makefile enforces a coverage floor of 95 percent for the internal/extension/plugin package specifically, which tells you that package is treated as a tested contract rather than an informal helper.

Request tracing records the full request and response chain to a file. It is switched on through trace.enabled in the configuration or by one of the specific working modes, and the files are organised as session/model name/category/sequence.json with three categories covering chat, response and Anthropic traffic. The point of the layout is that you can diff a single conversion step against the original call without reading a log file.

Usage statistics aggregate tokens and cost by session. There is also a web search injection feature that can run automatically or on demand and supports two search backends, Tavily and Firecrawl, and a prompt cache with three modes named explicit, automatic and hybrid. The README lists these features but does not document their configuration keys, so the practical route is the configuration reference rather than the README itself.

## Building and first run: binary, source tree or container

There are three documented ways to get Moon Bridge running, and each one ends with the same web console.

After installing the binary with pacman or by placing it on the path, the whole start sequence is one command. Running it with no configuration writes $HOME/moonbridge/config.yml, and the console is served at http://127.0.0.1:38440/console/ where providers, models and API keys are entered. From a source checkout the equivalent is a go run, and the README states that source development requires Go 1.25 or newer.

```bash
moonbridge
go run ./cmd/moonbridge
```

The container path builds an image and maps the port, mounting your configuration file into the expected location.

```bash
docker build -t moonbridge .
docker run -p 38440:38440 -v $(pwd)/config.yml:/config/config.yml moonbridge
```

The Dockerfile is worth reading even if you never use it. It builds with CGO disabled, produces a static binary with the symbol table stripped, and copies that binary into a distroless static Debian image running as a nonroot user. The default command line inside the container is -config /config/config.yml -addr 0.0.0.0:38440, which is why the docker run command above mounts the file to that exact path and publishes port 38440.

## Pointing Codex CLI and Claude Code at the local proxy

The integration story is short because the client side is already a standard OpenAI style endpoint. For Codex CLI you set the base URL to the proxy's /v1 path and give it any non-empty key, since the key is not what identifies you to Moon Bridge.

```toml
[openai]
base_url = "http://127.0.0.1:38440/v1"
api_key = "any-non-empty-value"
```

The README then says to define routes in the Moon Bridge configuration using the same model names Codex uses, which is what makes the alias resolution line up. There is also a -print-codex-config <model> switch that generates a ready config.toml for a named model and exits, so the exact file contents can be produced by the tool rather than typed by hand.

Claude Code is wired through command line flags instead, passing an alias through --model and pointing at the root of the proxy rather than at /v1.

```bash
claude --model your-alias --api-url http://127.0.0.1:38440 --api-key any-value
```

Because the alias is what selects the upstream, a single Claude Code invocation can be pointed at Anthropic, Gemini or an OpenAI chat upstream just by changing the alias in the routes section. That is the workflow the whole project exists to support.

## A Workers target, a licence, and no tagged releases

Two things about the repository's shape matter for a decision to depend on it. The first is that it is not only a server. The root package.json is named moonbridge-worker, and its build script compiles a separate binary to WebAssembly with tinygo for a cmd/cloudflare entry point, then deploys with wrangler. The repository also holds a webui/ directory that the Makefile builds with npm and copies into internal/service/webui/dist, so the embedded console is a frontend asset compiled separately from the Go code.

That is a wide surface: a Go server, a browser console and a Cloudflare Workers deployment path. A team that only needs a local binary can ignore two thirds of it, but a team evaluating the project should be clear about which of the three they intend to operate.

The second is release and licence shape. The project is licensed GPL v3, which carries obligations if you distribute a modified binary, so a team embedding it in a proprietary product should read the licence text rather than take the README's one line summary at face value. The repository has no GitHub releases at all, so there is no version history to pin against, and no changelog to read. The last push was on 2026-08-24 and the repository is not archived, which means work continues but there is no published artifact numbering to rely on when you need to reproduce an environment.

## Conclusion

Adopt Moon Bridge when you want Codex CLI or Claude Code pointed at a single local endpoint while the actual models live with different providers, and when you are comfortable with GPL v3 and with routing logic expressed in YAML. Do not adopt it as a general API gateway, because it only translates three inbound shapes and its management API and hot reload need persistence to be enabled. Verify first that the upstream protocol you need is one of the four named in the README, then check the models, providers and routes blocks in config.example.yml against the provider you intend to use before writing your own configuration.

## FAQ

### How do I start Moon Bridge for the first time?

Run the moonbridge binary with no configuration. It creates $HOME/moonbridge/config.yml on first start, and you then open http://127.0.0.1:38440/console/ to add providers, models and API keys. From a source checkout, go run ./cmd/moonbridge does the same thing and needs Go 1.25 or newer.

### Which upstream model providers can Moon Bridge talk to?

The README names Anthropic Messages, Google Gemini through the GenAI interface, and OpenAI Chat Completions as upstream protocols, alongside the OpenAI Responses API that Moon Bridge itself exposes at /v1/responses. The routes section of the YAML configuration maps a model alias to a provider and its upstream model name.

### Does Moon Bridge have released versions I can pin to?

The repository has no GitHub releases, so there is no published version list. The last push was on 2026-08-24 and the repository is not archived. The project is licensed GPL v3.

## Sources

- [Issues](https://github.com/ZhiYi-R/moon-bridge/issues)
- [License: GPL-3.0](https://github.com/ZhiYi-R/moon-bridge/blob/main/LICENSE)
- [README](https://github.com/ZhiYi-R/moon-bridge/blob/main/README.md)
- [ZhiYi-R/moon-bridge on GitHub](https://github.com/ZhiYi-R/moon-bridge)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/zhiyi-r-moon-bridge
