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: openaiPoint 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.