# Coding agent walkthrough (/docs/get-started/coding-agent/walkthrough)



Once the skill is [installed](/docs/get-started/coding-agent/install), adding TokenPolice is
four short touchpoints. Everything else — reading your code, writing the edits, checking the
result — the agent does on its own.

We'll follow one real example throughout: a **FastAPI support chat** that calls OpenAI.

<Steps>
  <Step>
    ### 1. Say the word [#1-say-the-word]

    Ask your agent, in plain language, to add TokenPolice:

    > **You:** Integrate TokenPolice into this app.

    That's the whole trigger. Wordings like &#x2A;"add TokenPolice"&#x2A;, &#x2A;"wrap my agent for
    TokenPolice"&#x2A;, or &#x2A;"track and enforce LLM spend"* work too — and the skill also wakes up on
    its own if you mention `tp.init`, `tp.workflow`, or `TokenPoliceBlockedError`.

    The agent reads your repo first. For the support chat it comes back with something like:

    > **Agent:** Found a FastAPI app calling OpenAI from `chat.py`. It's a multi-turn support
    > chat with a `session_id` per conversation and a `user.id` on the request. I'll wire
    > TokenPolice around the chat handler. First I need a few things from you.
  </Step>

  <Step>
    ### 2. Answer its questions [#2-answer-its-questions]

    The agent asks one short batch — nothing it could find in the code itself:

    * **Your API key*&#x2A; — &#x2A;"Create one on the API Keys page (app.tokenpolice.ai/keys). It looks
      like `tp_sk_...` and is shown only once, so copy it when created. I'll put it in your
      environment, never in source."* See [Get your API key](/docs/get-started/api-key).
    * **The collector URL** — where usage metadata is sent. The default is
      `https://collect.tokenpolice.ai`; you only change it if you self-host or run a local stack.
    * **Who your users are** — which field is the `user_id`, which is the plan/tier, and which
      is the `session_id`. For the support chat the agent already spotted `user.id` and
      `session_id` and just confirms them.
    * **Dry-run or enforce** — it starts in **dry-run** by default: every call is recorded and
      you can see what *would* have been blocked, but nothing is ever blocked. Flipping to
      enforce later is a one-line change.
    * **What a blocked call should return** (HTTP apps only) — for the FastAPI app, `429 Too
      Many Requests` or `402 Payment Required`. Only relevant once you turn on enforce.

    <Callout type="info">
      It also states the privacy terms up front: TokenPolice receives only token metadata —
      model, token counts, your chosen `user_id` / plan / `session_id` tags, and a content
      fingerprint used for loop detection. Raw prompt and completion text never leave your
      servers. See [Data & privacy](/docs/concepts/data-privacy).
    </Callout>
  </Step>

  <Step>
    ### 3. Approve the plan [#3-approve-the-plan]

    Before touching a single file, the agent shows you exactly what it will change:

    > **Agent:** Here's the plan:
    >
    > * `pip install token-police`
    > * Call `tp.init(...)` at startup in `main.py`, before the OpenAI client is imported,
    >   with `firewall="dry_run"`.
    > * Wrap the chat handler in `chat.py` with `@tp.workflow`, passing `user_id=user.id`,
    >   `paid_plan=user.plan`, and `session_id=session_id`.
    > * Add `TOKENPOLICE_API_KEY` to your `.env` and `.env.example`.
    >
    > Approve?

    You reply **yes** or ask for a change. No code is edited until you approve.
  </Step>

  <Step>
    ### 4. Run your app once [#4-run-your-app-once]

    The agent makes the edits, then asks you to run the app the way you normally would and send
    it a couple of messages — a normal request and a multi-turn conversation.

    That run is the test. When you say you're done, the agent **verifies itself**: it checks that
    TokenPolice actually recorded your traffic (using the same key you already gave it — never
    your app, never another key) and reports the result:

    > **Agent:** Verified — status **pass**. TokenPolice recorded your calls with the right
    > user and session tags. You're in dry-run mode, so nothing is blocked yet; flip
    > `firewall` to `"enforce"` when you're ready. See your data at app.tokenpolice.ai.

    You're done. Open [app.tokenpolice.ai](https://app.tokenpolice.ai) and your calls are there,
    with token counts and cost.
  </Step>
</Steps>

## What "verified" means [#what-verified-means]

The agent doesn't call the job done just because the code compiles. It confirms TokenPolice
**received real data** from your run and that your identity tags came through — then reports
`pass`, `warn` (with anything worth knowing), or `fail`. It won't stop on a `fail`.

<Accordions>
  <Accordion title="What the agent does under the hood">
    Behind those four touchpoints, the skill runs a disciplined flow so it never breaks your
    app: it reads your whole repo first, asks only what the code can't answer, writes a plan and
    waits for your yes, makes the smallest diff that does the job, reviews its own change for
    breakage, and then verifies against real traffic — retrying the fix-and-verify loop if the
    first run turns up a problem. You only ever see the four steps above; the rest is the agent
    keeping itself honest.
  </Accordion>
</Accordions>

## After you're set up [#after-youre-set-up]

<Cards>
  <Card title="Dry-run vs enforce" href="/docs/concepts/dry-run-vs-enforce" description="Turn on blocking when your rules look right." />

  <Card title="Firewall & Budgets" href="/docs/rules/overview" description="Set the caps and rules the firewall enforces." />

  <Card title="Nothing in the dashboard?" href="/docs/troubleshooting/nothing-in-dashboard" description="Common first-run fixes." />

  <Card title="What it did, step by step" href="/docs/get-started/integration-checklist" description="The same procedure written out — useful for reviewing the diff." />

  <Card title="See it in a running app →" href="/docs/sample-apps/support-agent" description="A full support-desk chat with the SDK already wired in — clone and run it." />
</Cards>
