burn

Setup

burn routes by the first path segment. A request to /openai/v1/chat/completions goes to the configured OpenAI URL with /v1/chat/completions appended. The query string is preserved.

Built-in providers

Route prefixProviderUpstream URLAPI format
/openaiOpenAIhttps://api.openai.comopenai
/anthropicAnthropichttps://api.anthropic.comanthropic
/openrouterOpenRouterhttps://openrouter.ai/apiopenai
/deepseekDeepSeekhttps://api.deepseek.comopenai
/groqGroqhttps://api.groq.com/openaiopenai
/geminiGemini (OpenAI compatibility)https://generativelanguage.googleapis.com/v1beta/openaiopenai

The formats matter for usage parsing and price matching. openai reads prompt_tokens, completion_tokens, cached-token details, and reasoning-token details. anthropic reads input_tokens, output_tokens, cache_read_input_tokens, and cache_creation_input_tokens.

OpenAI

Start the proxy, then set the base URL in your OpenAI client:

import OpenAI from 'openai';
 
const client = new OpenAI({
  baseURL: 'http://127.0.0.1:8787/openai/v1',
});

The SDK still reads OPENAI_API_KEY from the environment. burn forwards the authorization header upstream without reading or storing it.

Anthropic

The Anthropic SDK appends /v1/messages, so the base URL stops at /anthropic:

import Anthropic from '@anthropic-ai/sdk';
 
const client = new Anthropic({
  baseURL: 'http://127.0.0.1:8787/anthropic',
});

If you add /v1 here, requests will go to /anthropic/v1/v1/messages and the provider will return a 404.

Other providers

Any endpoint that speaks the OpenAI chat completions format can be routed through burn. Add it once:

burn provider add local http://127.0.0.1:11434/v1 openai

Then point the client at the new route:

import OpenAI from 'openai';
 
const client = new OpenAI({
  baseURL: 'http://127.0.0.1:8787/local/v1',
});

The same works for vLLM, LM Studio, a gateway, or a provider that exposes an OpenAI-compatible endpoint. Use anthropic as the format for an endpoint that speaks the Anthropic messages API:

burn provider add my-gateway https://gateway.example.com anthropic

burn run

burn run avoids setting environment variables by hand. It starts a proxy on an ephemeral port, sets the OpenAI and Anthropic base URLs for the child process, runs the command, closes the proxy, and prints a summary:

burn run -- node ./agent.js

Everything after -- is the command. The command inherits its normal environment plus:

OPENAI_BASE_URL=http://127.0.0.1:<random-port>/openai/v1
ANTHROPIC_BASE_URL=http://127.0.0.1:<random-port>/anthropic

The child process exit code becomes burn's exit code. If nothing was logged, burn prints a hint to check that the SDK picked up the base URL. The proxy exists only for that command, so a long-running editor or server process should use burn proxy instead.

burn env

burn env prints the export lines without starting a proxy:

burn env
export OPENAI_BASE_URL=http://127.0.0.1:8787/openai/v1
export ANTHROPIC_BASE_URL=http://127.0.0.1:8787/anthropic

It accepts --port when your proxy is on a different port:

burn env --port 8788

Paste the lines into your shell, or use eval "$(burn env)" in a POSIX shell. The command does not modify your shell by itself.

Tagging requests

Send an x-burn-tag header and the row is tagged:

const client = new OpenAI({
  baseURL: 'http://127.0.0.1:8787/openai/v1',
  defaultHeaders: { 'x-burn-tag': 'nightly-evals' },
});

Or with fetch:

await fetch('http://127.0.0.1:8787/openai/v1/chat/completions', {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
    'x-burn-tag': 'nightly-evals',
  },
  body: JSON.stringify({
    model: 'gpt-4o-mini',
    messages: [{ role: 'user', content: 'Hello' }],
  }),
});

The tag is stored on the row, truncated to 200 characters, and stripped before the request goes upstream. Group by it with:

burn by-tag --since 7d

Adding a provider

burn provider add <name> <url> [openai|anthropic]
  • name must be a single path segment: letters, digits, dots, dashes, and underscores. It becomes the first path segment of the local route.
  • url must start with http:// or https://. Trailing slashes are removed.
  • The format is optional and defaults to openai.

List the providers burn knows about:

burn provider

The list shows the built-in providers and the ones in your config, with a source column that says built in or yours.

Remove a custom provider:

burn provider remove <name>

Built-in providers cannot be removed with this command. Add a custom entry with the same name to override one, or use a different name for your route.

Starting the proxy

$ npx @xnah/burn proxy

If the proxy is already running in another terminal, do not start a second one on the same port. Use --port for a second instance, or stop the first one with Ctrl+C.