Connect an upstream #

Tabslip forwards calls to your provider using the client's existing credentials. Change the client's base URL to the local route below. The setup guide explains how your coding agent connects a project and how to undo its changes.

Provider Client base URL at the default port
OpenAI http://127.0.0.1:4545/openai/v1
OpenRouter http://127.0.0.1:4545/openrouter/v1
Ollama http://127.0.0.1:4545/ollama/v1
Anthropic http://127.0.0.1:4545/anthropic

For another provider, add an entry to your Tabslip config file. See the default config paths, or choose a file with tabslip serve --config ./config.yaml. Keep any existing settings and upstream entries. Use the provider's original URL without its final API /v1 suffix:

upstreams:
  - name: my-provider
    base_url: https://provider.example/api
    api: openai

Point the OpenAI-compatible client at http://127.0.0.1:4545/my-provider/v1. For Anthropic Messages, use api: anthropic and a client URL ending in /my-provider. Custom upstreams load at startup. Restart a running server to load changes.

Supported listen inputs are 127.0.0.1, localhost, ::1, 0.0.0.0 and ::. Wildcard inputs expose the proxy while keeping the Page URL on loopback. Flags override YAML before the effective listen address is checked.

An app in Docker on Linux #

With docker run --network host ..., the app can reach the host's loopback address and use the URLs above.

With bridge networking, add --add-host=host.docker.internal:host-gateway to docker run, then use http://host.docker.internal:4545/openai/v1, or the route for your upstream. The hostname alone does not make loopback reachable. Start Tabslip with tabslip serve --listen 0.0.0.0 so the proxy is reachable from the container. Specific non-loopback listen addresses are not supported. Check access from the container. Use the selected port if it differs from 4545.

The proxy forwards credentials without added authentication. Restrict access to the app with host networking rules. The page stays loopback-only; exposing the proxy does not expose the page. The printed Page URL uses loopback. Ask the owner before restarting an existing instance or changing its listen address.

A server beside your app #

Run Tabslip beside the app and use its loopback address. Reach the page with ssh -N -L 4545:127.0.0.1:4545 user@server, then open http://127.0.0.1:4545. The local port must equal the remote Tabslip port because the page checks the port in the browser's Host header. Use the selected port on both sides and in the local page URL. That local port must be free. The tunnel ends with Ctrl+C. Tabslip must keep running while the app routes through it. The agent setup instructions explain how to run it in the background. The undo guide explains how to stop an instance you started and restore the app's original URL.

Forwarding and tags #

Receipts cover these POST endpoints:

API JSON Streaming Captured fields when provided
/v1/chat/completions Yes SSE Model, id, provider, finish reason, fingerprint, input/output/cache/reasoning tokens, reported cost
/v1/responses Yes SSE Model, id, API status, usage, errors; terminal incomplete/failed status preserved
/v1/embeddings Yes No Model and input usage; output tokens stay unknown
Anthropic /v1/messages Yes SSE Model, id, stop reason, uncached input, cache reads/writes and output tokens

Credentials stay in the client: Authorization, x-api-key and provider headers pass through. Tabslip strips hop-by-hop headers and its own X-Tabslip-* headers. It does not retry provider calls. All paths forward, but receipt capture only covers POST chat completions, Responses, embeddings and Anthropic Messages at their /v1 API paths.

Direct OpenAI and Ollama streaming chat requests get stream_options.include_usage=true when needed. Custom OpenAI-compatible upstreams also inject usage by default; use inject_usage: false on an entry to disable it. OpenRouter, Responses, embeddings and Messages requests stay unchanged. Receipts record edits and hash the original client body.

For example, using the existing key and a saved OpenAI base URL:

curl -fsS "$OPENAI_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'X-Tabslip-Tag: my-project' \
  -d '{"model":"gpt-4.1","messages":[{"role":"user","content":"Hello"}]}'

This may cost money with a live provider. For a key-free check, use the demo's printed OpenAI base URL and OPENAI_API_KEY=demo. Tags accept 1–64 letters, digits, dots, underscores or hyphens. Invalid tags are not recorded. A tag is metadata that can appear in shared exports. Use the SDK's per-request headers for a temporary tag, or default headers for a lasting project tag, as in the OpenRouter example.

OpenRouter generation enrichment sends a follow-up GET with the same in-memory authorization, up to three attempts within ten seconds. It creates a signed supplement when successful and leaves the base receipt usable on failure. enrich_openrouter: false disables it after restart. Custom upstream names cannot replace presets or local page routes. Do not put keys in config. See privacy and the command reference.