> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firedog.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# How it works

> The split-plane architecture: a collector that prices every AI call inside your VPC, and a cloud dashboard that only ever sees metadata.

Firedog is built on one hard rule: the content of your AI calls never leaves your network. It achieves this with a split-plane design. A **collector** runs inside your own VPC and holds the full record of every call; the **Firedog cloud dashboard** receives only priced metadata and turns it into the reconciled bill. This page walks the architecture end to end.

## The two planes

<CardGroup cols={2}>
  <Card title="Collector — data plane" icon="server">
    Runs **inside your VPC**. Exposes an OpenAI-compatible endpoint, forwards each call to the upstream provider, prices it, and writes the **full record** to a **local Postgres you own**. Prompts, RAG chunks and responses live here and stay here.
  </Card>

  <Card title="Firedog cloud — control plane" icon="chart-column">
    The dashboard. Receives **metadata only** through the ingest API — tokens, cost, latency, model, and the attribution tags you set. It attributes and charts the spend. It never receives prompt or response content.
  </Card>
</CardGroup>

The boundary between the two is the whole point. Everything sensitive stays on the data plane. Only the numbers you need to reconcile a bill cross to the control plane.

<Info>
  The collector speaks the OpenAI Chat Completions API, so most apps adopt it with a base-URL swap or the `@firedog/sdk` client. See [/quickstart](/quickstart) to route your first call.
</Info>

### What crosses the boundary, and what does not

<Tabs>
  <Tab title="Stays in your VPC (CallRecord)">
    The **full record** is written to your local Postgres and is never emitted:

    * Prompt messages
    * Any RAG chunks or retrieved context
    * The model's response
    * The priced usage and latency for that call

    A drill-down in the dashboard fetches this record **from the collector, within your VPC** — on demand, correlated by `callId`. It is never copied to the cloud.
  </Tab>

  <Tab title="Crosses to Firedog cloud (CallMetadata)">
    Only metadata is emitted to the ingest API:

    ```json theme={null}
    {
      "callId": "01JAB...",
      "tenantId": "acme",
      "collectorId": "vpc-1",
      "timestamp": "2026-07-12T14:02:11Z",
      "model": "opus",
      "promptTokens": 4120,
      "completionTokens": 380,
      "cost": 0.0903,
      "latencyMs": 2140,
      "team": "macro-desk",
      "workflow": "market-research",
      "userHash": "u_9f3a…",
      "category": "research",
      "qaOverall": 4.4,
      "shadowSaving": 0.061
    }
    ```

    No prompt, no chunks, no response. `userHash` is a **salted hash**, never the raw identity. What is included is governed by your sensitivity profile — see [Security](/security).
  </Tab>
</Tabs>

The `callId` is a ULID minted client-side. It is the only thing that links the full VPC record to the cloud metadata, which is what lets a dashboard drill-down reach back into the collector for detail without the content ever having left.

## The life of a call

<Steps>
  <Step title="Your app calls the collector">
    Your application sends a normal Chat Completions request, either through the `@firedog/sdk` client or a plain base-URL swap. Attribution context travels as headers — `x-firedog-call-id`, `x-firedog-team`, `x-firedog-workflow`, `x-firedog-user` — so the collector knows which desk and workflow to file the call under.
  </Step>

  <Step title="The collector mints or receives the callId">
    If the SDK already minted a `callId`, the collector uses it; otherwise it mints one. This ULID will correlate the full local record with the cloud metadata for the rest of the call's life.
  </Step>

  <Step title="It forwards to the upstream provider">
    The collector forwards the request to the real provider using your `apiKey`, and receives the completion. It is a transparent proxy on the request path.
  </Step>

  <Step title="It prices the call">
    Using a shared pricing table (per-model input/output rates), the collector computes the exact cost from the returned token counts — for example `opus` at 15/75 USD per 1M tokens.
  </Step>

  <Step title="It writes the full record to local Postgres">
    The complete `CallRecord` — prompt, chunks, response, usage — is persisted to the Postgres instance **in your VPC**. This is the audit-grade source of truth, and it never leaves your network.
  </Step>

  <Step title="It emits metadata-only to Firedog cloud">
    The collector sends `CallMetadata` to the ingest API. What it is permitted to include is decided by your sensitivity profile. Content is never part of this payload.
  </Step>

  <Step title="The dashboard attributes and charts it">
    Firedog cloud files the metadata under its workflow, model and desk, reconciles it against the vendor invoice, and renders it across the five dashboard views.
  </Step>
</Steps>

<Note>
  A drop-in proxy user who does not use the SDK sets the same `x-firedog-*` headers directly. The attribution model is identical either way.
</Note>

## The two planes, drawn

```mermaid theme={null}
flowchart LR
  subgraph VPC["Your VPC — data plane"]
    App["Your app<br/>(SDK / base-URL swap)"]
    Collector["Collector<br/>forward · price · record"]
    PG[("Local Postgres<br/>full CallRecord")]
    App -->|"Chat Completions<br/>+ x-firedog-* headers"| Collector
    Collector -->|"full record"| PG
  end

  Provider["Upstream LLM provider"]
  Collector -->|"forward request"| Provider
  Provider -->|"completion"| Collector

  subgraph Cloud["Firedog cloud — control plane"]
    Ingest["Ingest API"]
    Dash["Dashboard<br/>5 views"]
    Ingest --> Dash
  end

  Collector -.->|"CallMetadata only<br/>(no content)"| Ingest
  Dash -.->|"drill-down by callId<br/>(fetched inside VPC)"| PG

  classDef boundary stroke-dasharray:4 4;
  class Cloud boundary;
```

The solid arrows are the request path and the full record, all inside your VPC. The **dashed arrow crossing the boundary carries metadata only**. The return dashed arrow shows a drill-down: the dashboard asks for detail by `callId`, but that detail is fetched from the collector within your VPC — it is never stored in the cloud.

<Warning>
  Content never crosses the boundary. If a payload to the ingest API ever contained a prompt, chunk or response, that would be a defect, not a configuration choice. Redaction and hashing behaviour is tuned by the sensitivity profile; the content boundary itself is not configurable.
</Warning>

## What the dashboard shows

Once metadata is flowing, the same reconciled dollars are sliced five ways:

<CardGroup cols={2}>
  <Card title="Home" icon="receipt">
    The reconciled bill per workflow, where tagged plus untagged equals the vendor total to the cent.
  </Card>

  <Card title="Cost allocation" icon="chart-pie">
    The same dollars sliced by workflow, desk, tool, model and use-case, with an exportable spend report.
  </Card>

  <Card title="Workflow detail" icon="diagram-project">
    Step by step why one run costs what it does — the re-read tax, made visible.
  </Card>

  <Card title="Answer quality" icon="clipboard-check">
    LLM-judge pass rates per model and use-case, from a sampled score.
  </Card>

  <Card title="Audit trail" icon="file-shield">
    A per-call evidence ledger, plus measured cheaper-model savings from shadow testing.
  </Card>
</CardGroup>

<Tip>
  Ready to see it end to end? Route one call in the [Quickstart](/quickstart), then confirm the boundary in [Security](/security).
</Tip>
