The gateway routes. Cruise prices.
Run Cruise as the OpenAI-compatible backend behind agentgateway. No plugin, no fork, no image of ours — and every response still says which job it was booked to, which model answered and where the budget stands. A recipe that has been run, including the trap that costs an afternoon.
Per-request cost attribution survives the mesh edge
A proxy is free to strip response headers it does not recognise, and one that did would cost every caller behind it their budget state and their cost attribution. agentgateway passes them through. Every response that came back through it carried:
x-cruise-lane: bb/code-review the job this call was booked against
x-cruise-model: anthropic/claude-fable-5-1 who actually answered
x-cruise-selection: cheap why that one
x-cruise-budget-state: ok ok, or the reason the next call gets refused
x-cruise-budget-spend: 0.0000 spent this period
x-cruise-budget-limit: 5.00 the hard cap
x-cruise-budget-period: dayThe recipe’s smoke test asserts on these headers, so an upstream change that turned the gateway into a plain proxy hop would fail it.
On Kubernetes: the 400 that never mentions TLS
Cruise is agentgateway’s openai provider with the host pointed at Cruise. On Kubernetes, TLS to that host has to be stated — an AgentgatewayBackend does not infer it from port: 443. We removed exactly one block and put it back:
policies.tls | Result |
|---|---|
| omitted | 400 · The plain HTTP request was sent to HTTPS port |
sni: cruise-demo.bytesbrains.net | 200, Cruise headers intact |
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayBackend
metadata:
name: cruise
namespace: cruise
spec:
ai:
groups:
- providers:
- name: cruise
openai: {}
host: cruise-demo.bytesbrains.net
port: 443
path: /v1/chat/completions
policies:
auth:
secretRef:
name: cruise-api-key
tls:
sni: cruise-demo.bytesbrains.net # must match hostTwo things make it slow to debug when it bites:
- It is not a
BackendTLSPolicy. Despite Gateway API habit, it isspec.ai.groups.providers[].policies.tlson the backend itself. A separate policy resource will not fix it. - The error never mentions TLS. The
400comes from the upstream’s edge — Cloudflare, for Cruise — so it reads like a malformed request and sends you to inspect your JSON. The body is fine. The connection was plaintext.
agentgateway’s own OpenAI-compatible providers page includes this block in every example and in its template; copy that and you are fine. The trap is in carrying a mental model across from the standalone config, where the two surfaces behave differently:
- Standalone — an
https://params.baseUrlexpands to host, path prefix and TLS. Nothing to configure. - Kubernetes —
policies.tls.snimust be stated, and must matchhost.
Lanes route with nothing in the gateway config
A catch-all model entry passes the request’s model id to Cruise unchanged, so every lane and every pinned model works without being listed. One call per lane, through the gateway:
| Lane requested | Model Cruise chose |
|---|---|
bb/summarization | deepseek/deepseek-flash |
bb/extraction | mistral/mistral-small-latest |
bb/code-review | anthropic/claude-fable-5-1 |
Which model serves a lane is Cruise’s decision, made per request — this is what that run reported, not a fixed mapping.
A hard cap refuses, through the gateway
Against the demo’s hard-cap project — emulated spend, nothing billed — served requests reported rising spend of 0.0040, 0.0060 and 0.0080. The next call came back 429 with error.code: budget_exhausted at 0.0100 and retry-after: 32. After the wait, a completion was served again. The refusal reaches an agent behind the gateway as a code it can branch on, not prose.
Try it in two commands
The standalone gateway in Docker, against the free demo — it costs nothing and exits non-zero if anything fails. Put a cru_demo_ key from the Cruise demo tab in .env, which is gitignored:
cp .env.example .env
./smoke.shThe whole standalone config:
llm:
port: 4000
providers:
- name: cruise
provider: openAI
params:
baseUrl: $CRUISE_BASE_URL # https:// turns TLS on by itself
apiKey: $CRUISE_API_KEY
models:
- name: "*" # every lane and model, none listed
provider:
reference: cruiseThis runs on agentgateway’s unreleased 1.x build, pinned by digest. The newest published release, 0.8.2, rejects the llm: block outright. The Kubernetes path runs on released versions.
Failure modes worth recognising
| What you see | What it is |
|---|---|
400 The plain HTTP request was sent to HTTPS port | No policies.tls on a Kubernetes backend. |
401 Incorrect API key provided. | Cruise refused the key, relayed intact. Often a cru_demo_ key against production, or the reverse. |
401 Missing bearer token. | No key reached Cruise: the Secret’s key is not named Authorization, or the example Secret was applied unedited. |
llm: unknown field | agentgateway too old for the standalone config — 0.8.2 rejects it. |
A cf-ray header on a response means the request reached Cruise rather than dying in the gateway.
What this page does not claim
- That it was run against production Cruise — every call went to the demo.
- That agentgateway endorses or lists Cruise. It does not.
- Any agentgateway version beyond the ones above.
More about Cruise: the product · pricing

