# Prove your savings from a file (no routing)

Paste the prompt below into the coding agent working in your repository.
It instruments your app to write a JSONL capture file of real requests and
responses. You upload that one file at https://dashboard.paritylayer.com/dashboard/offline and
Parity proves, on your own prompts, that a cheaper model matches or beats
your current one, then projects your savings.

No traffic is routed through Parity, and nothing leaves your side except
the single file you choose to upload. Unlimited free proving, no credit
card.

```text
You are instrumenting this codebase to produce a capture file for Parity Layer
(paritylayer.com) — WITHOUT routing any traffic through a third party. Parity
Layer uses the file to prove a cheaper model matches your current model's
output quality on your real prompts, then projects your savings.

GOAL: one file, ./parity-capture.jsonl, holding 100 real request/response
pairs for EACH distinct prompt this app runs, plus true call volume.

Do exactly this:

1. Find every place this app calls an LLM provider (OpenAI, Anthropic, or an
   OpenAI-compatible API).

2. Give each distinct logical prompt a short stable id — its "tag" (e.g.
   "summarize-ticket"). Every call running the same logical prompt must log
   the SAME tag. Use a tag for ANY prompt that may run more than 100 times
   during the capture window — the volume summary in step 6 only works for
   tagged prompts. If a low-traffic prompt has no natural id, omit the tag
   (Parity Layer will fingerprint it from the message content) and do NOT
   cap it — log every call.

3. Wrap each call so that, immediately after the provider responds, you append
   ONE JSON object per line (JSONL) to ./parity-capture.jsonl:
   - "tag": the stable prompt id from step 2
   - "timestamp": ISO-8601 UTC time of the call — REQUIRED (used to project
     your true monthly volume)
   - "model": the exact model string called (e.g. "gpt-4o")
   - "provider": "openai" | "anthropic" | ...
   - "request_body": the RAW provider request object. It MUST contain a
     non-empty "messages" array. If a call does not use chat-messages shape
     (e.g. the OpenAI Responses API), convert it faithfully to
     {"messages": [{"role": ..., "content": ...}]} when logging.
   - "response_body": the RAW provider response object in its FINAL,
     non-streaming shape (an OpenAI chat completion or an Anthropic message).
     Do not truncate or reshape it. For streamed calls, assemble the complete
     final response (full content + usage) and log that.
   - "cost_usd": what this call cost you — REQUIRED for the savings
     projection. If you do not already track per-call cost, compute it from
     the response's token counts x the provider's current list prices for
     that model.
   - "prompt_tokens" and "completion_tokens": from the response's usage.
   - Optional: "latency_ms", "cache_read_tokens", "cache_creation_tokens",
     "cache_hit".
   OMIT any field you do not have a value for — never write null.
   Logging is append-only and must NEVER block, slow, or alter the real call.
   If logging fails, the app must behave exactly as before.

4. Only log (and count) a line if the response contains a real assistant
   message — non-empty text content or tool calls. Never log provider
   ERROR responses as capture lines.

5. Stop at 100 logged lines per tag — then keep counting. Parity Layer proves
   each prompt on its first 100 captures. After a tag reaches 100 full lines,
   log no more full lines for it; count every further call instead.

6. Run for AT LEAST 24 hours of wall-clock time under normal production
   traffic, even if every tag reaches its 100 much sooner — the savings
   projection is computed from the capture window and needs a full daily
   cycle. Keep counting calls until the window ends.

7. When the capture window ends, append ONE summary line for EVERY tag —
   not only the busy ones — using the same tag as its logged lines and the
   full window:
   {"type":"volume_summary","tag":"<id>",
    "observed_requests":<total calls for this tag in the window, including
      the logged ones>,
    "window_start":"<iso start of the whole capture window>",
    "window_end":"<iso end of the whole capture window>",
    "per_model":[{"model":"...","count":N,"avg_prompt_tokens":...,
      "avg_completion_tokens":...,"avg_baseline_cost_usd":...,
      "cache_hit_rate":...}]}
   Omit any per_model number you do not have — never write null.
   Low-traffic prompts that never reach 100 in the window are fine — log
   whatever happens.

8. NEVER log secrets, API keys, or auth headers — only the fields above.

When the file is ready, upload ./parity-capture.jsonl in the Parity Layer
dashboard under "Offline import". Parity Layer proves parity from it and
shows your projected savings. Nothing from your side is sent anywhere except
this one file you upload.
```

Ready to route live traffic instead? See
<https://paritylayer.com/docs/agent-setup.md>.
