{"slug": "agent-bridge-an-openai-compatible-api-for-headless-coding-agent-clis", "title": "Agent-bridge – an OpenAI-compatible API for headless coding-agent CLIs", "summary": "An independent project called agent-bridge, a Go HTTP server released under the GNU GPL v3 or later, exposes an OpenAI-compatible API at /v1/chat/completions and /v1/models and fulfils each request by running the official Claude Code CLI in headless mode (claude -p --output-format stream-json). The server also supports the OpenAI Codex CLI (codex exec --json) and the Kimi Code CLI (kimi acp, over the Agent Client Protocol) as backends, letting clients such as LangChain, LlamaIndex, CrewAI, AutoGen and the OpenAI Python, Node and Go SDKs switch to it by changing only base_url, api_key and model. It requires the claude CLI version 2.1.128 or later plus one interactive login, ships as a single binary for Linux, macOS and Windows on amd64 and arm64, and is not developed, endorsed or supported by Anthropic.", "body_md": "**English** · [Italiano](https://github.com/R3n3r0/agent-bridge/blob/main/README.it.md)\n\n`agent-bridge` is an HTTP server written in Go that exposes an OpenAI-compatible\nAPI (`/v1/chat/completions`, `/v1/models`) and fulfils every request by running\nthe official Claude Code CLI in headless mode\n(`claude -p --output-format stream-json`).\n\nIt can also run the OpenAI Codex CLI (`codex exec --json`) or the Kimi Code\nCLI (`kimi acp`, over the Agent Client Protocol) instead, with the same API:\nsee the [Codex backend](https://github.com/R3n3r0/agent-bridge/blob/main/docs/codex.md) and the [Kimi backend](https://github.com/R3n3r0/agent-bridge/blob/main/docs/kimi.md).\n\nAny client or framework that speaks OpenAI can use it by changing only\n`base_url`, `api_key` and `model`: chat, streaming, function calling (tool\ncalling) and image input work with the official SDKs unchanged.\n\nIn short: an **OpenAI-compatible API server, proxy and gateway for Claude\nCode**. It lets OpenAI-based multi-agent systems, ReAct orchestrators and\nframeworks that accept a custom OpenAI `base_url` (for example LangChain,\nLlamaIndex, CrewAI, AutoGen or the OpenAI SDKs for Python, Node and Go) use\nClaude Code headless as a drop-in chat completions model or as a coding agent,\nwith tool calling, MCP servers, sessions, streaming (SSE) and per-agent models.\nThe same server is an OpenAI-compatible API, proxy and gateway for the\nOpenAI Codex CLI and for the Kimi Code CLI (Moonshot AI, Kimi K2), and an\nACP (Agent Client Protocol) client.\n\n**Independent project.** agent-bridge is not developed, endorsed or\nsupported by Anthropic. It runs the official `claude` binary installed on\nthe machine, without modifying it, and never accesses its credentials.\n\n- Single binary, Go standard library only at runtime.\n- Linux, macOS and Windows (amd64 and arm64).\n- Same build for development (subscription login) and production (API key).\n- OpenAI function calling (`tools` ,`tool_calls` ), streaming included.\n- Image input (`image_url` parts: data URLs and http(s) URLs).\n- Three CLI backends: the default one, the OpenAI Codex CLI\n(`backend: \"codex\"` , see[docs/codex.md](https://github.com/R3n3r0/agent-bridge/blob/main/docs/codex.md) ) and the Kimi Code\nCLI (`backend: \"kimi\"` , see[docs/kimi.md](https://github.com/R3n3r0/agent-bridge/blob/main/docs/kimi.md) ).\n- Free software, licensed under the GNU GPL v3 or later.\n\n|  | As a model | As an agent on the server | \n|---|---|---|\n| Who defines the agent | Your client or platform: `system` ,`tools` , model choice | The bridge configuration file | \n| Available tools | Only the functions the client sends in `tools` , executed by the client | CLI tools on the server machine (files, commands, search, MCP servers), plus any client functions | \n| `model` | `bridge/opus` ,`bridge/sonnet` ,`bridge/haiku` ,`bridge/<model name>` | The name of the configured agent | \n| Configuration | None | JSON file | \n| Section | [Using it as a model](#using-it-as-a-model) | [Agents on the server](#agents-on-the-server) | \n\n\"Tools\" therefore come in two kinds, both supported:\n\n- **client functions** (OpenAI function calling): defined and executed by the\nclient; the model calls them through`tool_calls` ;\n- **agent tools** :`Read` ,`Edit` ,`Bash` , MCP servers… executed by the CLI on\nthe server, within the agent's permissions; the client only sees the final\nresult.\n\nPrerequisite: the `claude` CLI installed, version **2.1.128 or later**, and one\ninteractive login (`claude`).\n\n```\ngo install github.com/r3n3r0/agent-bridge/cmd/agent-bridge@latest\nAGENT_BRIDGE_AUTH_MODE=subscription agent-bridge\ncurl -s http://127.0.0.1:8787/v1/chat/completions \\\n  -d '{\"model\":\"bridge/haiku\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello!\"}]}'\n```\n\nWithout a configuration file the server listens on `127.0.0.1:8787` and accepts\nthe models `bridge/opus`, `bridge/sonnet`, `bridge/haiku` and\n`bridge/<model name>` (the name after the prefix is passed to the CLI as\nis; the `bridge/` prefix can be changed with `builtin_prefix`). They are\n*chat-only* models: no server tools, an empty temporary working directory,\nbut they accept client functions and images.\n\nAlternatively, download a binary from the releases page (archives and\n`checksums.txt` for every platform).\n\nThis is the scenario of a platform that already has its own agents, graph and lifecycle (for example a ReAct system): the bridge behaves like an OpenAI model and the agent is the one defined in the platform.\n\n| In the platform | In the request | \n|---|---|\n| Agent instructions | `system` message | \n| Agent tools | `tools` | \n| Model | `bridge/<alias or model name>` | \n\nTwo options make the bridge stateless and make the platform's agent the only agent. Set them in the configuration, or per request with a header:\n\n| Configuration key | Header | Effect | \n|---|---|---|\n| `client_tools.mode: \"stateless\"` | `X-Agent-Bridge-Tool-Mode: stateless` | After returning `tool_calls` the process exits: every request is one step of the graph and the history sent by the client is the only source of truth. Branches, retries and checkpoints stay in the platform | \n| `system_messages: \"replace\"` | `X-Agent-Bridge-System-Mode: replace` | `system` messages become the effective system prompt instead of the CLI one, at every step. With`append` they are added to it | \n\nRecommended configuration for this scenario:\n\n```\n{ \"client_tools\": { \"mode\": \"stateless\" }, \"system_messages\": \"replace\" }\n```\n\nIn this scenario do not send `X-Session-Id`: every request starts a new process\nwith the full history. It costs some latency per step, in exchange for no\nhidden state in the bridge.\n\nFunctions defined by the client with `tools` work as with the OpenAI API: the\nmodel answers with `tool_calls` and `finish_reason: \"tool_calls\"`, the client\nruns the functions and sends the results back as `role: \"tool\"` messages, and\nthe model continues. It also works when streaming (`delta.tool_calls`) and\nwithout session headers.\n\n```\nr = client.chat.completions.create(model=\"bridge/sonnet\", messages=messages, tools=tools)\nwhile r.choices[0].finish_reason == \"tool_calls\":\n    messages.append(r.choices[0].message)\n    for call in r.choices[0].message.tool_calls:\n        messages.append({\"role\": \"tool\", \"tool_call_id\": call.id,\n                         \"content\": run(call.function.name, call.function.arguments)})\n    r = client.chat.completions.create(model=\"bridge/sonnet\", messages=messages, tools=tools)\n```\n\nComplete example: [examples/python/tools.py](https://github.com/R3n3r0/agent-bridge/blob/main/examples/python/tools.py).\n\nSupported: `tools` (type `function`), `tool_choice` (`auto`, `none`,\n`required`, a specific function), `parallel_tool_calls` (parallel calls\nreturned together) and the deprecated `functions`/` function_call` format.\n\n**How it works.** Client functions are offered to the CLI as tools of a\nstandard MCP server, served by the bridge itself (internal `mcp-tools`\nsubcommand). When the model calls one, the bridge returns the call to the\nclient. Then, depending on `client_tools.mode`:\n\n| Mode | What happens | When to choose it | \n|---|---|---|\n| `stateful` (default) | The process waits; the request carrying the results is recognized by its `tool_call_id` s and the same process resumes where it stopped | Simple clients: lower latency between steps | \n| `stateless` | The process exits; the request carrying the results starts a new process with the full history | Orchestrators with their own state (see [Using it as a model](#using-it-as-a-model) ) | \n\nDifferences to be aware of:\n\n- `tool_choice` other than`auto` /`none` and`parallel_tool_calls: false` are\nexpressed as instructions to the model: the model follows them, but they\nare not hard constraints as in the OpenAI API. Function`parameters` schemas (and`strict` ) also guide the model but are not enforced.\n- In `stateful` mode the waiting process holds a concurrency slot. If the\nresults do not arrive within`client_tools.wait_timeout_seconds` (default\n600) the process is stopped; a later request with the results starts a new\nprocess from the full history, so it still works.\n- With the deprecated `functions` format results carry no id: every call ends\nthe process, as in`stateless` mode.\n- In a `tool_calls` response`usage` covers only the model's last message;\nturn totals are in the logs and in`/stats` .\n\nMessages can contain `image_url` parts, as in the OpenAI API, with any model:\n\n```\nr = client.chat.completions.create(model=\"bridge/sonnet\", messages=[{\"role\": \"user\", \"content\": [\n    {\"type\": \"text\", \"text\": \"What is in this picture?\"},\n    {\"type\": \"image_url\", \"image_url\": {\"url\": \"data:image/png;base64,...\"}},\n]}])\n```\n\n- **Sources** :`data:` URLs (base64) and`http(s)` URLs, which the bridge\ndownloads. Downloads from non-public addresses (loopback, private networks,\ncloud metadata) are refused unless`images.allow_private_networks` is set;`images.fetch_urls: false` accepts only`data:` URLs.\n- **Formats** : PNG, JPEG, GIF, WebP, recognized from the content. Up to`images.max_count` images per request (default 20) and`images.max_bytes` each (default 5 MB); the whole input, images included, must stay within\n9 MB.\n- **How** : images are sent to the CLI as image blocks of a structured\nmessage (`--input-format stream-json` ); the text refers to them as`[image 1]` ,`[image 2]` … in order. Requests without images keep plain-text\ninput.\n- In a resumed session only the images of the new messages are sent; earlier\nones are already in the session. `images.enabled: false` rejects images with\n400`unsupported_content` .\n\nThe bridge drives the CLI, not the model API directly, so it supports the OpenAI parameters the CLI can express, and emulates two more:\n\n| OpenAI parameter | How | Fidelity | \n|---|---|---|\n| `reasoning_effort` | CLI `--effort` ;`none` /`minimal` become`low` ,`xhigh` and`max` are accepted as an extension | Direct | \n| `response_format` (`json_object` ,`json_schema` ) | CLI `--json-schema` : the answer is validated against the schema and returned as compact JSON in`content` | Direct, validated | \n| `max_tokens` ,`max_completion_tokens` | `CLAUDE_CODE_MAX_OUTPUT_TOKENS` for the process | Partial: limits every model response of the turn, not the turn total; `finish_reason` is not set to`length` | \n| `stop` (string or up to 4) | The final text is cut at the first occurrence | Emulated: the model still generates the full answer; never applied to `response_format` JSON or to progress texts | \n| `n` (1-8) | `n` independent processes in parallel, one choice each, also when streaming | Emulated: costs `n` times; no session resume, and client functions run stateless | \n| `temperature` ,`top_p` ,`seed` ,`logprobs` ,`presence_penalty` ,`frequency_penalty` ,`logit_bias` | — | Accepted and ignored: the CLI has no equivalent | \n\nIf `response_format` cannot be satisfied (the CLI gives up after its retries,\nor ends without structured output), the request fails with 502.\n\nA JSON file maps a model name to an agent: model, system prompt, CLI tools, permissions and working directory. Use it when the agent must work on the server machine, for example on a repository.\n\n```\n{\n  \"agents\": {\n    \"reviewer\": {\n      \"model\": \"opus\",\n      \"system_prompt\": \"You are a strict reviewer. Do not modify files.\",\n      \"allowed_tools\": [\"Read\", \"Grep\", \"Glob\"],\n      \"cwd\": \"/srv/project\"\n    },\n    \"coder\": {\n      \"model\": \"sonnet\",\n      \"allowed_tools\": [\"Read\", \"Edit\", \"Write\", \"Bash(go test *)\"],\n      \"permission_mode\": \"acceptEdits\",\n      \"cwd\": \"/srv/project\"\n    }\n  }\n}\nagent-bridge check-config -config agents.json   # validate and print the resolved agents\nAGENT_BRIDGE_AUTH_MODE=subscription agent-bridge -config agents.json\n```\n\nThe client picks the agent with the `model` field:\n\n``` python\nfrom openai import OpenAI\nclient = OpenAI(base_url=\"http://127.0.0.1:8787/v1\", api_key=\"unused\")\nr = client.chat.completions.create(\n    model=\"reviewer\",\n    messages=[{\"role\": \"user\", \"content\": \"Review the error handling.\"}],\n    extra_headers={\"X-Session-Id\": \"review-42\"},\n)\nprint(r.choices[0].message.content)\n```\n\nAn agent on the server can also receive client functions in `tools`: it will\nuse both its own tools and those.\n\nFull reference: [docs/configuration.md](https://github.com/R3n3r0/agent-bridge/blob/main/docs/configuration.md). Annotated\nexample: [examples/agents.example.json](https://github.com/R3n3r0/agent-bridge/blob/main/examples/agents.example.json).\n\n- **Without `X-Session-Id`** (OpenAI behavior): every request starts a new\nprocess; the history sent by the client is turned into a single prompt.\n- **With `X-Session-Id`** (or the` user` field): the same key resumes the CLI\nsession with`--resume` , and the CLI receives only the new messages (user\nmessages and tool results) after the assistant's last answer. Faster in long\nconversations. The key, generated when missing, is always returned in the`X-Session-Id` response header.\n- `system` messages are placed at the top of the prompt\n(`system_messages: \"prompt\"` , default): in a resumed session only those of\nthe first turn count. With`append` or`replace` they are passed as the\nsystem prompt and apply to every turn.\n- Answers to `tool_calls` in`stateful` mode resume the waiting process through\nthe`tool_call_id` s, regardless of the session.\n\nThe mode is chosen only by configuration, with the mandatory\n`AGENT_BRIDGE_AUTH_MODE` variable:\n\n| Mode | Use | Credentials | \n|---|---|---|\n| `subscription` | Development on your own machine | Login done with `claude` ;`ANTHROPIC_API_KEY` and`ANTHROPIC_AUTH_TOKEN` must not be set | \n| `api` | Production and shared instances | `ANTHROPIC_API_KEY` required (Claude Console key) | \n\nThe server refuses to start if the mode and the environment are inconsistent.\nIn `subscription` mode the API key variables are removed from the child\nprocess environment anyway, and if the CLI reports using an API key the server\nlogs an error on every turn.\n\nEvery turn records tokens and cost (logs, optional `usage_log` file, `/stats`,\n`/metrics`). **In `subscription` mode `cost_usd` is an estimate computed by the\nCLI at API prices, not a charge**: it helps forecast what production with an\nAPI key will cost.\n\n`compose.yaml` runs the bridge with all three CLIs, one service per backend\n(ports 8787, 8788 and 8789 on the host's loopback), sharing one home volume\nfor the CLIs' logins:\n\n```\nmake up       # creates .env with a random API key, builds, starts, prints the addresses\nmake admin    # opens the login page\nmake smoke    # one request to every service\n```\n\n`make help` lists the other targets (logs, doctor, terminal logins, update,\nreset). Without make: `cp .env.example .env`, set `AGENT_BRIDGE_API_KEY`,\n`docker compose up -d`.\n\nThen log in to the CLIs from the admin page, `http://127.0.0.1:8787/admin`:\nit runs each CLI's official login flow on the server and shows its link and\none-time code (or a box to paste the code back). The CLIs keep the\ncredentials; the bridge never reads them. Details: [docs/docker.md](https://github.com/R3n3r0/agent-bridge/blob/main/docs/docker.md).\n\nWith `backend: \"codex\"` (or `-backend codex`, `AGENT_BRIDGE_BACKEND=codex`)\nevery turn runs `codex exec --json` instead of the default CLI. The API,\nsessions, function calling, images, structured output and reasoning effort\nwork the same way; built-in models become `bridge/default` (the model\nconfigured in Codex) and `bridge/<model>`; agents with tools use a `sandbox`\n(`read-only`, `workspace-write`, `danger-full-access`) instead of\n`permission_mode` and `allowed_tools`. Authentication: `codex login` in\n`subscription` mode, `CODEX_API_KEY` in `api` mode.\n\n```\ncodex login\nAGENT_BRIDGE_AUTH_MODE=subscription agent-bridge -backend codex\n```\n\nFull mapping, agent fields and differences: [docs/codex.md](https://github.com/R3n3r0/agent-bridge/blob/main/docs/codex.md).\n\nWith `backend: \"kimi\"` (or `-backend kimi`, `AGENT_BRIDGE_BACKEND=kimi`) every\nturn runs `kimi acp`, the Kimi Code CLI as an Agent Client Protocol agent,\nwith the bridge as the ACP client. The API, sessions, function calling,\nimages, structured output and reasoning effort work the same way; built-in\nmodels become `bridge/default` (the default model of Kimi Code) and\n`bridge/<model>`; the bridge answers the CLI's permission requests from\n`allowed_tools`, `disallowed_tools` and `permission_mode` (`default`, `plan`,\n`auto`, `yolo`). Authentication: `kimi login` in `subscription` mode,\n`KIMI_MODEL_NAME` and `KIMI_MODEL_API_KEY` in `api` mode. ACP reports no token\nusage or cost.\n\n```\nkimi login --region global   # kimi.ai; mainland-cn for kimi.com\nAGENT_BRIDGE_AUTH_MODE=subscription agent-bridge -backend kimi\n```\n\nFull mapping, agent fields and differences: [docs/kimi.md](https://github.com/R3n3r0/agent-bridge/blob/main/docs/kimi.md).\n\nagent-bridge is a tool: whoever uses it remains responsible for complying with the terms of their plan. In short:\n\n1. **No access to credentials.** The code never reads, copies, stores, logs or\nforwards credential files or tokens. Login happens only through the CLI's\nofficial flow, and the subscription token is never used to call the API\ndirectly.\n2. **One subscription, one user.** In`subscription` mode the server must serve\nonly the account holder, on their own machine. The default configuration\nlistens on loopback only; remote access must be enabled explicitly and is\nmeant for reaching your own instance from your own laptop (e.g. a personal\nVPN), not for other users.\n3. **Shared instances only with an API key.** An instance used by several\npeople (e.g. a lab or a team) must run in`api` mode with the owner's key,\nwithout reselling or brokering costs.\n\nReferences, to be checked again because **the rules may change**:\n\nAn agent on the server with tools enabled can read, write and run commands: whoever reaches the server has the equivalent of a restricted shell. Defaults are closed and every opening is explicit.\n\n- **Network.** Listens on`127.0.0.1:8787` by default. A non-loopback address\nrequires`allow_remote: true` (or`-allow-remote` )**and**`AGENT_BRIDGE_API_KEY` . There is no built-in TLS: for remote access use a\nreverse proxy with TLS, an SSH tunnel or a VPN.\n- **Client authentication.** With`AGENT_BRIDGE_API_KEY` set,`/v1/*` ,`/stats` and`/metrics` require`Authorization: Bearer <key>` (constant-time\ncomparison).`/healthz` and`/readyz` stay open.\n- **CORS** is disabled; enable it with an exact list of origins\n(`cors_origins` ), no wildcards.\n- **`bridge/*` models** are always chat-only: no server tools, in any\nmode.\n- **Client functions** are executed only by the client, never on the server.\nCalls go through an internal broker on`127.0.0.1` with a random port and a\ndifferent token for every turn; the turn's files are private and removed at\nthe end.\n- **Per-request overrides** (`X-Agent-Cwd` ,`X-Agent-Allowed-Tools` ,`X-Agent-System-Prompt` ) are rejected with 403 unless enabled in`overrides` ; they can only narrow tools, the directory must be inside an\nallowed root (also after resolving symlinks), and the system prompt is only\nappended. Never applicable to`bridge/*` models.\n- **`system_messages`.** With` replace` the CLI system prompt is replaced by\nthe request's messages (the agent's`system_prompt` stays first); the\npermissions of the agent's tools do not change.\n- **`bypassPermissions`** is rejected unless` allow_bypass_permissions: true` ,\nin which case a warning is printed at startup for every affected agent.\n- **Logs.** At`info` level and above, prompts and answers are never logged;\nat`debug` they are truncated to 500 characters.`sk-ant-…` keys and the\nbridge key are replaced with`[REDACTED]` in logs and errors.\n- **Processes.** Every turn is a separate process, started without a shell,\nwith the prompt on stdin. Timeouts, client disconnection or server shutdown\nterminate the whole process tree (process group on Unix,`taskkill /T` on\nWindows).\n\nClient examples:\n\n- Go with the official SDK: [examples/go](https://github.com/R3n3r0/agent-bridge/blob/main/examples/go/main.go)\n- Python with the official SDK: [examples/python/client.py](https://github.com/R3n3r0/agent-bridge/blob/main/examples/python/client.py)\n- Python, function calling: [examples/python/tools.py](https://github.com/R3n3r0/agent-bridge/blob/main/examples/python/tools.py)\n- Python, images: [examples/python/images.py](https://github.com/R3n3r0/agent-bridge/blob/main/examples/python/images.py)\n- curl: [examples/curl.sh](https://github.com/R3n3r0/agent-bridge/blob/main/examples/curl.sh)\n\nEndpoints:\n\n| Method and path | Purpose | \n|---|---|\n| `POST /v1/chat/completions` | Runs a turn (JSON or SSE) | \n| `GET /v1/models` ,`GET /v1/models/{id}` | Lists configured agents and `bridge/*` aliases (`bridge/<model name>` names answer the detail endpoint but are not listed); the prefix follows`builtin_prefix` | \n| `GET /stats` | Per-agent statistics; `?reset=true` resets them after returning them | \n| `GET /metrics` | Prometheus metrics (with `metrics: true` ) | \n| `GET /healthz` ,`GET /readyz` | Liveness and readiness | \n\nRequest headers:\n\n| Header | Effect | \n|---|---|\n| `X-Session-Id` ,`X-Session-Reset` | Session to resume or restart | \n| `X-Agent-Bridge-Tool-Mode` | `stateful` or`stateless` for client functions | \n| `X-Agent-Bridge-System-Mode` | `prompt` ,`append` or`replace` for`system` messages | \n| `X-Agent-Cwd` ,`X-Agent-Allowed-Tools` ,`X-Agent-System-Prompt` | Overrides, only if enabled | \n| `X-Request-Id` | Identifier reported in logs and in the response | \n\nResponse headers: `X-Session-Id`, `X-Request-Id` and, in non-stream responses,\n`X-Agent-Bridge-Turns`, `X-Agent-Bridge-Cost-USD`, `X-Agent-Bridge-Duration-Ms`.\n\nAdmin page (with `admin: true` or `AGENT_BRIDGE_ADMIN=1`): `GET /admin` and\n`/admin/api/logins` to log in to the CLIs ([docs/docker.md](https://github.com/R3n3r0/agent-bridge/blob/main/docs/docker.md)).\n\nCommands: `agent-bridge serve` (default), `check-config`, `doctor [-live]`,\n`version`; `mcp-tools` is internal, started by the CLI for client functions.\n`doctor` checks the CLI and its version, the consistency of the authentication\nmode and directory permissions; with `-live` it runs a test turn on Haiku (with\nthe Codex and Kimi backends: the model configured in the CLI, and for Codex\n`codex login status`).\n\n- `temperature` ,`top_p` ,`seed` ,`logprobs` ,`presence_penalty` ,`frequency_penalty` and`logit_bias` are accepted and ignored;`stop` ,`n` and`max_tokens` are emulated or partial (see[Generation parameters](#generation-parameters) ).\n- Function calling: a binding `tool_choice` ,`parallel_tool_calls: false` and\nfunction schemas are instructions to the model, not enforced constraints.\n- Content parts other than text and `image_url` (audio, files) return 400`unsupported_content` ;`detail` on images is accepted and ignored.\n- No support for `/v1/responses` ,`/v1/embeddings` , image generation, audio,\nor other providers.\n- Prompts up to 9 MB (the CLI limits stdin to 10 MB).\n- When streaming, the `X-Agent-Bridge-Turns` ,`-Cost-USD` and`-Duration-Ms` response headers are not available (headers are sent before execution);\ncost and tokens are in the logs, in`/stats` and in the`usage` chunk when\nrequested with`stream_options.include_usage` .\n- When streaming, progress is sent as single-line SSE comments without a following blank line, because some SDKs treat a blank line after a comment as an empty event.\n- A turn can take minutes: the model may work through several steps before answering.\n- The exact values of the `apiKeySource` field of the`init` event are not\ndocumented: the server treats only`none` as \"no API key\".\n\n**Does it support tools?** Yes, of two kinds: client functions through OpenAI\nfunction calling, and agent tools on the server (files, commands, search, MCP\nservers) for configured agents. See [Two ways to use it](#two-ways-to-use-it).\n\n**Why don't `temperature` and `top_p` work?** The bridge drives the Claude\nCode CLI, which has no option for them, and calling the model API directly\nwould bypass the CLI (and, with a subscription, its terms). What the CLI does\noffer is mapped: see [Generation parameters](#generation-parameters).\n\n**Does it accept images?** Yes, `image_url` parts with `data:` or `http(s)`\nURLs, as in the OpenAI API. See [Images](#images).\n\n**Do I need to change my OpenAI client?** No: change `base_url`\n(`http://127.0.0.1:8787/v1`), `api_key` (the `AGENT_BRIDGE_API_KEY`, or any\nvalue if it is not set) and `model`.\n\n**Do I need a configuration file for every agent?** No, if agents are defined\nin the client: instructions in `system`, tools in `tools`, a `bridge/*`\nmodel. The file is only needed for agents that use the server's tools.\n\n**Is the context duplicated if I send the whole history?** Without\n`X-Session-Id` every request starts again from the full history, like a\nstateless API. With `X-Session-Id` the session is resumed and the CLI receives\nonly the new messages.\n\n**What happens if I change working directory mid-conversation?** CLI sessions\nare tied to the project directory: the server starts a new one.\n\n**Can I expose the server on the network?** Only explicitly (`allow_remote`\nplus `AGENT_BRIDGE_API_KEY`), behind TLS, and in `subscription` mode only for\nthe account holder. For several users use `api` mode.\n\n**Two requests on the same session?** They are serialized (`on_busy: wait`) or\nthe second gets 409 (`on_busy: reject`).\n\nLayered structure with interfaces and replaceable implementations:\n[docs/architecture.md](https://github.com/R3n3r0/agent-bridge/blob/main/docs/architecture.md). Full technical specification,\nrevision 1.4: [docs/specification.md](https://github.com/R3n3r0/agent-bridge/blob/main/docs/specification.md).\n\n```\ngo test -race ./...          # uses a fake CLI binary, no credentials\n./scripts/coverage.sh        # minimum coverage of the main packages\n```\n\nCI never uses the real CLI or credentials. Manual checks before every release\nare in [docs/release-checklist.md](https://github.com/R3n3r0/agent-bridge/blob/main/docs/release-checklist.md).\n\nagent-bridge is free software: you can redistribute it and/or modify it under\nthe terms of the GNU General Public License as published by the Free Software\nFoundation, either version 3 of the License, or (at your option) any later\nversion. See [LICENSE](https://github.com/R3n3r0/agent-bridge/blob/main/LICENSE).\n\nThe license covers this project's code only. Claude Code is a separate product with its own terms, installed and used by you under your agreement with Anthropic.", "url": "https://wpnews.pro/news/agent-bridge-an-openai-compatible-api-for-headless-coding-agent-clis", "canonical_source": "https://github.com/R3n3r0/agent-bridge", "published_at": "2026-10-18 12:02:28+00:00", "updated_at": "2026-10-18 12:17:48.648772+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "agent-protocols", "large-language-models"], "entities": ["agent-bridge", "Claude Code", "OpenAI Codex CLI", "Kimi Code CLI", "Moonshot AI", "Anthropic", "Agent Client Protocol", "LangChain"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/agent-bridge-an-openai-compatible-api-for-headless-coding-agent-clis", "markdown": "https://wpnews.pro/news/agent-bridge-an-openai-compatible-api-for-headless-coding-agent-clis.md", "text": "https://wpnews.pro/news/agent-bridge-an-openai-compatible-api-for-headless-coding-agent-clis.txt", "jsonld": "https://wpnews.pro/news/agent-bridge-an-openai-compatible-api-for-headless-coding-agent-clis.jsonld"}}