PUNKthe adaptive runtime

//DOCS 5-Minute Quickstart

Create an observe key, route one model request through Punk, and diagnose the exact run.

Five-Minute Quickstart

Send one real, low-risk request through Punk, then inspect the exact run that served it. This is the hosted path; the gateway origin is always https://app.punktechnologies.com.

For an enterprise rollout, use Enterprise Pilot after this first run. For the complete protocol and integration variants, continue with First Run, OpenAI Gateway, or Anthropic SDK.

1. Create the safe first-run setup

  1. Sign up at https://punktechnologies.com/signup and verify the email from
  2. Verify your email for Punk. Verification activates the trial's effective plan and quotas; it is not an API-key substitute.

  3. In https://app.punktechnologies.com, open Governance → API keys and
  4. create a key with these first-run settings:

SettingValue
Namesupport-app-observe
Modeobserve
App idsupport-app
Adminoff

Copy the pk_... token now. The app-pinned key keeps this integration scoped to support-app; it overrides any X-Punk-App value sent by the client. A non-admin observe key records traffic and always returns the live result—it cannot make an optimized route serve or enforce a blocking policy.

  1. Choose where the live answer comes from before sending a model request:
Response sourceChoose it whenSetup
Platform providerYour organization is entitled to use a provider already configured for its Punk workspace.Pick a supported model for that provider; no provider secret belongs in your app.
BYOK providerYour organization supplies its own OpenAI, Anthropic, OpenRouter, DeepSeek, or Moonshot/Kimi credential.Add the credential in Governance → Provider keys. Keep it out of application environment variables.

gpt-4o-mini needs an available OpenAI-compatible source; claude-sonnet-4-6 needs an available Anthropic source. A Punk tenant key authenticates your app to Punk—it is not an OpenAI or Anthropic key.

export PUNK_BASE_URL=https://app.punktechnologies.com
export PUNK_API_KEY=pk_...

2. Send one request

Use one of the equivalent examples below. Keep all three identity dimensions stable for this first check. X-Punk-Subject should be a pseudonymous user, account, ticket, or work-item id—not an email address or customer name.

curl

curl -sS -D /tmp/punk-headers -o /tmp/punk-body \
  "$PUNK_BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $PUNK_API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-Punk-App: support-app" \
  -H "X-Punk-Agent: triage-worker" \
  -H "X-Punk-Subject: ticket-123" \
  -d '{
    "model": "gpt-4o-mini",
    "temperature": 0,
    "messages": [{
      "role": "user",
      "content": "Classify this ticket: I was charged twice. Return JSON."
    }]
  }'

RUN_ID=$(awk 'tolower($1)=="x-punk-run-id:" {print $2}' /tmp/punk-headers | tr -d '\r' | tail -n 1)
ROUTE=$(awk 'tolower($1)=="x-punk-route:" {print $2}' /tmp/punk-headers | tr -d '\r' | tail -n 1)
jq -r '.choices[0].message.content' /tmp/punk-body
printf 'route=%s runId=%s\n' "$ROUTE" "$RUN_ID"

OpenAI SDK

npm install openai
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://app.punktechnologies.com/v1",
  apiKey: process.env.PUNK_API_KEY,
  defaultHeaders: {
    "X-Punk-App": "support-app",
    "X-Punk-Agent": "triage-worker",
    "X-Punk-Subject": "ticket-123",
  },
});

const { data, response } = await client.chat.completions.create({
  model: "gpt-4o-mini",
  temperature: 0,
  messages: [{ role: "user", content: "Classify this ticket: I was charged twice. Return JSON." }],
}).withResponse();

console.log(data.choices[0]?.message?.content);
console.log({
  route: response.headers.get("x-punk-route"),
  runId: response.headers.get("x-punk-run-id"),
});

Anthropic SDK

npm install @anthropic-ai/sdk @punktechnologies/sdk
import Anthropic from "@anthropic-ai/sdk";
import { createPunkAnthropicConfig } from "@punktechnologies/sdk/anthropic";

const client = new Anthropic(createPunkAnthropicConfig({
  baseUrl: "https://app.punktechnologies.com",
  apiKey: process.env.PUNK_API_KEY,
  app: "support-app",
  agent: "triage-worker",
  subject: "ticket-123",
}));

const { data, response } = await client.messages.create({
  model: "claude-sonnet-4-6",
  max_tokens: 256,
  messages: [{ role: "user", content: "Classify this ticket: I was charged twice. Return JSON." }],
}).withResponse();

console.log(data.content);
console.log({
  route: response.headers.get("x-punk-route"),
  runId: response.headers.get("x-punk-run-id"),
});

The Anthropic client receives the gateway origin (no /v1 suffix); it adds /v1/messages. The OpenAI client receives the /v1 base URL.

Punk TypeScript SDK

npm install @punktechnologies/sdk
import { Punk } from "@punktechnologies/sdk";

const punk = new Punk({
  baseUrl: "https://app.punktechnologies.com",
  apiKey: process.env.PUNK_API_KEY,
  app: "support-app",
  agent: "triage-worker",
  subject: "ticket-123",
});

const result = await punk.chat({
  model: "gpt-4o-mini",
  temperature: 0,
  messages: [{ role: "user", content: "Classify this ticket: I was charged twice. Return JSON." }],
});

console.log(result.content);
console.log({ route: result.route, runId: result.runId });
const detail = await punk.runDetail(result.runId);
console.dir(detail.run.routeExplanation, { depth: null });

3. Read the first result

With a working live provider and this observe key, the first response normally has x-punk-route: live. The run explanation should say that Punk selected live pass-through, record the provider/model and identity, and describe any cache miss or not-yet-eligible alternatives. live on the first run is the expected safe result, not a failed optimization.

Look up the exact run from any example:

curl -sS -H "Authorization: Bearer $PUNK_API_KEY" \
  "$PUNK_BASE_URL/api/v1/runs/$RUN_ID" \
  | jq '{
      id: .run.id,
      route: .run.route,
      provider: .run.provider,
      model: .run.model,
      app: .run.appId,
      agent: .run.agentId,
      subject: .run.subject,
      explanation: .run.routeExplanation
    }'

Open Runs in the dashboard and select the same run id. This ordinary run detail is the route explanation for every model request. A Chorus receipt is separate and is only expected for model: "punk/chorus"; retrieve one, when requested, at GET /api/v1/runs/:runId/receipt. Do not use a missing Chorus receipt to diagnose a normal gpt-* or claude-* run.

Integration diagnostics

SymptomCheckFix
401Request has no Authorization: Bearer pk_..., or the token was copied only partially.Create or copy a current Punk tenant key. Do not use an OpenAI/Anthropic key at the gateway.
No Punk run idOpenAI requests must use https://app.punktechnologies.com/v1; Anthropic and Punk SDK baseUrl use https://app.punktechnologies.com.Remove an accidental duplicate /v1, proxy URL, or direct provider base URL.
Provider error or mock providerThe selected model family has no usable platform provider/BYOK key, or local development explicitly forces PUNK_PROVIDER=mock.Add/select the matching provider source in Governance → Provider keys; in a local environment remove the mock setting when checking live traffic. An admin can use GET /api/v1/readiness; a non-admin app key correctly receives 403 there.
Model rejectedgpt-* and claude-* use different provider families.Use a model supported by the configured source, for example gpt-4o-mini for OpenAI-compatible or claude-sonnet-4-6 for Anthropic.
Quota or plan errorOpen Usage & billing and confirm the active organization, verified trial status, and remaining run quota.Verify the signup email, switch to the intended organization, or change the plan/quota with an owner or admin. GET /api/v1/usage shows the same tenant usage.
Wrong app/agent/subject in the runInspect the exact run lookup above.Send all X-Punk-* dimensions or constructor options. For an app-pinned key, use its pinned app id; Punk intentionally overrides a conflicting app header.

Once this run is clear, repeat the same low-risk request and use First Run for the longer observe → evidence → optimize path.