Threshold Docs  /  T8 Engine

T8 Engine

The data plane of Threshold — a stateless proxy that sits in front of upstream APIs (LLM providers, MCP servers, tool servers) and intercepts agent requests to enforce policies, swap credentials, and stream responses back.

Control-plane configuration is optional. T8 can run standalone with a TOML config and a rule-runner sidecar — see the t8 plugin for a one-command install.

Modes

ModeStatusHow the agent configures it
HTTPS PrefixImplementedBASE_URL=https://t8engine.com/https://api.anthropic.com
MCP ProxyImplementedBASE_URL=https://t8engine.com/mcp (JWT auth)
HTTP ProxyImplementedhttp_proxy=http://t8engine:1800
HTTPS Proxy (MITM)Implementedhttps_proxy=http://t8engine.com:1800 + CA from /ca.crt
HostnamePlannedGH_HOST=gh.t8engine.com

HTTPS Prefix Mode

The agent prepends the T8 base URL to the upstream API base URL. No SDK changes or custom code required — only environment variables.

Agent configuration

# Before (direct)
ANTHROPIC_API_KEY=sk-ant-real-key

# After (via T8)
ANTHROPIC_API_KEY=<t8-agent-key>
ANTHROPIC_BASE_URL=https://t8engine.com/https://api.anthropic.com

What T8 receives

POST /https://api.anthropic.com/v1/messages HTTP/1.1
Host: t8engine.com
Authorization: Bearer <t8-agent-key>
Content-Type: application/json

What T8 does

  1. Extracts the target URL from the path (https://api.anthropic.com/v1/messages).
  2. Finds a matching config entry (prefix + optional incoming_auth) and resolves credentials — see Credential Resolution.
  3. Strips the T8 agent key and any incoming_auth headers — they are internal and never forwarded.
  4. Strips hop-by-hop headers and request-scoped framing headers (host, content-length, content-encoding).
  5. Forwards the request to the upstream with the substituted credentials.
  6. Streams the response back, preserving status code, headers, and body encoding.

Both http:// and https:// prefixes are accepted.

HTTP Proxy Mode

The agent sets http_proxy=http://t8engine:1800. Any HTTP library that honours the standard http_proxy environment variable will automatically route plain-HTTP requests through T8 — no SDK changes or custom code required.

Agent configuration

export http_proxy=http://t8engine:1800

What the agent sends

GET http://api.example.com/v1/endpoint HTTP/1.1
Host: api.example.com
Authorization: Bearer <t8-agent-key>

What T8 does

  1. Receives the request with an absolute URI in the request line.
  2. Extracts the target URL directly from the request URI.
  3. Applies the same credential resolution as HTTPS Prefix mode (config → control plane → pass-through).
  4. Forwards the request to the upstream and streams the response back.

This mode covers plain-HTTP upstream APIs. For HTTPS upstreams, use HTTPS Proxy (MITM) Mode, which handles CONNECT tunnelling.

Credential Resolution

T8 resolves credentials through three branches, tried in order. The first match wins.

1. Config file (static)

A TOML file mapping URL prefixes to upstream headers. Loaded once at startup.

[[routes]]
    prefix = "https://api.anthropic.com"
    [routes.headers]
        authorization = "Bearer sk-ant-..."

[[routes]]
    prefix = "https://api.openai.com"
    [routes.headers]
        authorization = "Bearer sk-proj-..."

The first entry whose prefix matches the start of the target URL and whose incoming_auth headers (if any) all match the request is selected. See Config File Format for details.

2. Control plane (dynamic)

When CONTROL_PLANE_URL is set and the request carries a Bearer t8ak_… token (a T8 Agent Key issued by the control plane), T8 exchanges it for upstream credentials:

POST /t8/credentials
Authorization: Bearer t8ak_<agent-key>
{"target_host": "api.anthropic.com"}

→ {"headers": {"authorization": "Bearer sk-ant-real-key"}}

This enables per-agent credential management via the Threshold admin UI without touching any config files.

3. Pass-through

If no config entry matches and no T8 Agent Key is present, the request is forwarded as-is. Non-t8ak_ authorization headers are forwarded unchanged.

HTTPS Proxy (MITM) Mode

T8 acts as an HTTP CONNECT proxy. The agent sets https_proxy, and T8 intercepts each HTTPS tunnel by terminating TLS with a dynamically-generated host certificate signed by the T8 CA.

What T8 does

  1. Client sends CONNECT api.anthropic.com:443 HTTP/1.1 to T8.
  2. T8 responds 200 Connection Established.
  3. T8 wraps the socket in TLS using a per-hostname cert signed by the T8 CA.
  4. Decrypted HTTP requests go through the same credential resolution as HTTPS Prefix Mode.
  5. T8 forwards to the upstream and streams the response back.

Quick install (one-liner)

T8 serves a self-installing script that downloads the CA cert and adds it to the system trust store:

curl -fsSL http://t8engine:1800/ca.sh | sh

The script auto-detects Debian/Ubuntu, Alpine, RHEL/Fedora, Arch, and macOS. It also prints the environment variables needed for Node.js, Python, and curl.

Manual setup

# 1. Download the CA cert
curl -fsSL http://t8engine:1800/ca.crt -o t8-engine-ca.crt

# 2. Install it (pick your platform below)

# 3. Point your agent at T8
export https_proxy=http://t8engine:1800

Debian / Ubuntu / Devcontainers

sudo cp t8-engine-ca.crt /usr/local/share/ca-certificates/t8-engine-ca.crt
sudo update-ca-certificates

Alpine

sudo cp t8-engine-ca.crt /usr/local/share/ca-certificates/t8-engine-ca.crt
sudo update-ca-certificates

RHEL / Fedora / CentOS

sudo cp t8-engine-ca.crt /etc/pki/ca-trust/source/anchors/t8-engine-ca.pem
sudo update-ca-trust extract

macOS

sudo security add-trusted-cert -d -r trustRoot \
  -k /Library/Keychains/System.keychain t8-engine-ca.crt

Docker (in a Dockerfile)

# Alpine or Debian-based image
COPY t8-engine-ca.crt /usr/local/share/ca-certificates/t8-engine-ca.crt
RUN update-ca-certificates

Language-specific trust

Some runtimes don't use the system trust store by default:

# Node.js
export NODE_EXTRA_CA_CERTS=/path/to/t8-engine-ca.crt

# Python (requests / httpx)
export REQUESTS_CA_BUNDLE=/path/to/t8-engine-ca.crt
# or:
export SSL_CERT_FILE=/path/to/t8-engine-ca.crt

# curl (if system store was not updated)
curl --cacert /path/to/t8-engine-ca.crt ...

CA persistence

By default T8 generates a random CA at startup. Clients must re-install the CA cert after each restart. Three options to make it stable:

Option 1 — Seed (simplest). Set a hex seed and T8 derives a deterministic key pair. No files to manage.

# Generate a seed once:
openssl rand -hex 32
# → e.g. a1b2c3d4...

# Pass it to T8:
T8_CA_SEED=a1b2c3d4... docker compose up -d t8engine

Option 2 — Explicit PEM. Full control over the CA cert and key.

# Generate a persistent CA with openssl (run once):
openssl ecparam -name prime256v1 -genkey -noout | \
  openssl pkcs8 -topk8 -nocrypt -out ca.key
openssl req -new -x509 -key ca.key -out ca.crt -days 3650 -subj "/CN=T8 Engine CA"

# Pass it to T8:
T8_CA_CERT=$(cat ca.crt) T8_CA_KEY=$(cat ca.key) docker compose up -d t8engine

Option 3 — None. T8 generates a fresh CA every time. Fine for local development; fetch the cert from GET /ca.crt or run the install script after each restart.

MCP Proxy Mode

Routes under /mcp are reverse-proxied to the configured upstream MCP server. Requests must carry a valid EdDSA JWT issued by the control plane.

Agent → GET /mcp/... → T8 → MCP_UPSTREAM + MCP_UPSTREAM_PATH

JWT validation fetches the JWKS from JWKS_URL on first request and caches it.

Protocol Support

ProtocolHTTPS PrefixHTTP ProxyHTTPS Proxy (MITM)MCP Proxy
HTTP/1.1 request/response
Server-Sent Events / chunked stream
WebSocket (Upgrade: websocket)❌ (rejected)
HTTP/2

Server-Sent Events

Streaming responses (text/event-stream, NDJSON, chunked transfer-encoding) flow through T8 chunk-by-chunk. Each chunk is forwarded to the client as soon as it arrives from the upstream — T8 never buffers the response body.

WebSocket

T8 forwards HTTP upgrade requests through the same credential-resolution flow as regular requests (config entry → control plane → pass-through). After the upstream returns 101 Switching Protocols, T8 pipes the client and upstream sockets bidirectionally and stops inspecting traffic on that connection.

  • HTTPS Prefix: clients connect to wss://t8engine.com/https://target.example.com/ws. The path-prefix is stripped and the request is forwarded.
  • HTTP Proxy / HTTPS Proxy (MITM): clients use the proxy as normal. T8 sees an Upgrade: websocket request after CONNECT + TLS termination, applies credential resolution, and forwards.
  • Reserved paths (/healthz, /ca.crt, /ca.sh, /mcp/*) reject upgrades with 404.
  • MCP: the upstream MCP server uses streamable-HTTP, not WebSocket, so upgrades on /mcp/* are intentionally rejected.

HTTP/2

T8 speaks HTTP/1.1 only — both inbound and outbound. Clients that negotiate HTTP/2 will fall back to HTTP/1.1:

  • Inbound: Fastify is configured without http2: true, and MITM TLS sockets do not advertise the h2 ALPN protocol.
  • Outbound: the undici client used to call upstreams is HTTP/1.1.

In practice this is only visible to clients that try to negotiate HTTP/2 with T8 directly. Clients using T8 as an HTTPS proxy (CONNECT) negotiate HTTP/2 with the upstream end-to-end before TLS interception kicks in — which means HTTP/2 over MITM is also unsupported (the MITM TLS terminator forces http/1.1 ALPN).

Configuration (environment variables)

All configuration is via environment variables.

VariableDefaultDescription
PORT1800Port T8 listens on
MCP_UPSTREAMhttps://threshold.inversed.aiUpstream MCP server base URL
MCP_UPSTREAM_PATH/mcp/test/Path prefix rewritten on MCP proxy requests
JWKS_URL{MCP_UPSTREAM}/.well-known/jwks.jsonJWKS endpoint for MCP JWT verification
JWT_ISSUER{MCP_UPSTREAM}Expected iss claim in MCP JWTs
CONTROL_PLANE_URL(unset)Threshold backend URL for dynamic credential lookup. Omit to disable.
T8_CONFIG(unset)TOML credential config as an inline string. Takes precedence over T8_CONFIG_FILE.
T8_CONFIG_FILE(unset)Path to TOML credential config file. Used only if T8_CONFIG is not set.
RULE_RUNNER_URL(unset)URL of the rule-runner service. When unset, t8 skips rule evaluation (default-allow).
T8_CA_SEED(unset)Hex seed (≥32 chars) to derive a deterministic CA key. Simplest persistence option.
T8_CA_CERT(unset)PEM CA certificate for HTTPS MITM. Overrides T8_CA_SEED if both set.
T8_CA_KEY(unset)PEM EC private key for the CA. Required when T8_CA_CERT is set.

Config File Format

The TOML config has two top-level sections:

  • [[routes]] — credential injection + URL rewriting per upstream.
  • [[rules]] — JS/TS permission rules evaluated on every proxied request (see the Rule Scripts reference).

All string values support ${VAR_NAME} interpolation. An unset variable is a startup error; empty string is allowed.

Route entries

Each entry matches requests whose target URL starts with prefix. First match wins. Headers from the matched entry are merged into the outgoing request, overriding anything the client sent under the same names — typically used to swap an agent-facing token for the real upstream credential.

# Minimal entry: inject an Authorization header on every Anthropic request.
[[routes]]
    prefix = "https://api.anthropic.com"
    [routes.headers]
        authorization = "Bearer ${ANTHROPIC_API_KEY}"

Custom header (e.g. x-api-key) instead of Authorization:

[[routes]]
    prefix = "https://api.openai.com"
    [routes.headers]
        "x-api-key" = "${OPENAI_API_KEY}"

Rewrite mode — agent calls https://example/..., T8 forwards to https://actual-api.example.com/.... Useful for hiding the real upstream host behind a stable alias the agent can hard-code:

[[routes]]
    prefix = "https://example"
    rewrite_prefix = "https://actual-api.example.com"
    [routes.headers]
        authorization = "Bearer ${EXAMPLE_API_KEY}"

incoming_auth — per-route proxy authentication

[routes.incoming_auth] gates a route behind headers the caller must present. It is part of entry matching: an entry only matches if all incoming_auth headers equal the values in the request. Headers listed in incoming_auth are always stripped before the request is forwarded — they never reach the upstream.

[[routes]]
    prefix = "https://api.anthropic.com"

    [routes.incoming_auth]
        authorization = "Bearer alice-proxy-token"  # caller must present this

    [routes.headers]
        authorization = "Bearer sk-ant-alice"       # forwarded upstream instead

Multiple entries for the same host with different incoming_auth values act as per-account routes — the caller's token selects which upstream credential is used:

[[routes]]
    prefix = "https://api.openai.com"
    [routes.incoming_auth]
        authorization = "Bearer alice-proxy-token"
    [routes.headers]
        authorization = "Bearer sk-openai-alice"

[[routes]]
    prefix = "https://api.openai.com"
    [routes.incoming_auth]
        authorization = "Bearer bob-proxy-token"
    [routes.headers]
        authorization = "Bearer sk-openai-bob"

A request that matches no entry's incoming_auth falls through to the control plane or pass-through branches — there is no explicit rejection.

Agent key headers

By default T8 scans Authorization, x-api-key, x-goog-api-key, and api-key for a t8ak_… token or a backend-issued JWT. Add to this list only when a target API uses a non-standard header for credentials:

agent_key_headers = ["x-custom-auth"]

Rules

Permission rules live alongside routes as [[rules]] blocks. They run for every proxied request, in declaration order — first deny wins. Full contract: see the Rule Scripts reference.

[[rules]]
id = "block-evil"
script = """
function rule(ctx) {
  if (ctx.kind !== 'http') return { action: 'allow' };
  if (ctx.host.endsWith('evil.com')) {
    return { action: 'deny', reason: 'host blocked' };
  }
  return { action: 'allow' };
}
"""

The rule-runner URL is configured via the optional RULE_RUNNER_URL env var. When unset, t8 skips rule evaluation entirely (default-allow). The t8 plugin compose file wires this to a bundled rule-runner service automatically.

Running

Via the t8 plugin (recommended)

The t8 marketplace ships a Claude Code skill that generates a Docker Compose stack (t8engine + rule-runner), the route TOML, optional rules, and the CA install instructions for your platform. From inside Claude Code:

/plugin marketplace add Inversed-Tech/t8
/plugin install t8engine-setup@t8

Then: "set me up with t8engine locally".

Docker Compose (manual)

Published images:

ghcr.io/inversed-tech/t8engine:v0.1
ghcr.io/inversed-tech/rule-runner:v0.1

Pass credentials via the T8_CONFIG environment variable (no volume mount required):

# Inline config from a file
T8_CONFIG=$(cat /path/to/config.toml) docker compose up -d t8engine

# Connect to a running control plane
CONTROL_PLANE_URL=http://backend:8000 docker compose up -d t8engine

T8_CONFIG_FILE is also supported for environments where a volume mount is available (e.g. production). T8 is available at http://localhost:1800.

Health check

curl http://localhost:1800/healthz
# {"status":"ok"}