Metadata-Version: 2.4
Name: cygnos-capture-proxy
Version: 0.1.0
Summary: Local pass-through capture endpoint for AI API traffic — the first Cygnos capture source.
Author-email: Cygnos AI Private Limited <hello@cygnos.ai>
License-Expression: LicenseRef-Proprietary
Project-URL: Homepage, https://cygnos.ai
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Developers
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: starlette>=0.37
Requires-Dist: uvicorn>=0.29
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic>=2
Requires-Dist: cygnos-shared[schema]>=0.1.0
Provides-Extra: brotli
Requires-Dist: brotli>=1.1; extra == "brotli"
Provides-Extra: zstd
Requires-Dist: zstandard>=0.22; extra == "zstd"
Provides-Extra: all
Requires-Dist: brotli>=1.1; extra == "all"
Requires-Dist: zstandard>=0.22; extra == "all"
Dynamic: license-file

# Connect your AI usage — Cygnos Capture Proxy

A lightweight local process that gives Cygnos visibility into your AI API usage.
It is a **pass-through reader, never a modifier**: it forwards every request to
the provider **unchanged** and emits one usage event per call to Cygnos. It
never filters, blocks, rewrites, retries, or injects anything. Claude Code is
the first supported client; more capture sources are coming.

> A bug in Cygnos is a bad dashboard, never a bad prompt — that's the whole
> design. The proxy only *observes*.

---

## Prerequisites (2 minutes)

1. A **Cygnos account** and an **organisation that has been approved** (you'll
   see the dashboard, not the "access under review" screen).
2. An **API key**: in the dashboard, open **API Keys** → *Create key* → copy the
   `cygnos_sk_…` value. You only see it once. (Events from an unapproved org are
   rejected, so make sure your org is approved first.)

## Install

```bash
pip install cygnos-capture-proxy
```

Python 3.10 or newer. That is the whole install — no Cygnos repository, no clone,
no build step. It brings its own dependencies and puts a `cygnos-capture` command
on your PATH.

gzip and deflate response streams are read out of the box. If your traffic comes
back brotli- or zstd-encoded, add the optional decoders (without them those
responses still pass through untouched — only the token counts on those events
are missed):

```bash
pip install "cygnos-capture-proxy[all]"
```

## Configure (the two env vars)

```bash
export CYGNOS_API_KEY="cygnos_sk_your_key_here"
export CYGNOS_INGEST_URL="https://<your-cygnos-host>/events"
```

## Run

```bash
cygnos-capture                 # or: python -m cygnos_capture_proxy
```

You'll see a startup line like:

```
Cygnos Capture Proxy on http://127.0.0.1:8788 → upstream https://api.anthropic.com → ingest https://…/events (session 1f2e…)
```

It binds to `127.0.0.1` only — nothing is exposed on your network.

### The binding banner — read it before you walk away

Immediately after that line the proxy checks, against your Cygnos backend, whether
your key actually resolves to an organisation, and says so in plain words. This is
the one thing worth reading at startup, because a broken key is otherwise invisible:
your AI tools keep working perfectly while nothing reaches your dashboard.

A good binding looks like this — the organisation named is the tenant your events
will land under, so check it is the one you meant:

```
Cygnos capture binding: OK — Your Cygnos API key was accepted.
  Organisation: Acme Robotics (org_2f9c…)
  Events will be sent to https://…/events
```

A broken one is loud and tells you what to do about it:

```
───────────────────────────────────────────────────────────────────────────
CYGNOS CAPTURE IS NOT BOUND — captured events will NOT reach your dashboard.

  What is wrong: Cygnos does not recognise this API key, or it has been revoked.
                 Every event will be rejected.
  What to do:    Check CYGNOS_API_KEY against the API Keys page. A key is shown once
                 at creation; if it was mangled or revoked, create a new one.

  Your AI tools are UNAFFECTED. This proxy will keep forwarding every request
  to the provider normally. Only Cygnos capture is broken.
───────────────────────────────────────────────────────────────────────────
```

A failed binding does **not** stop the proxy, on purpose: a Cygnos problem must never
become an outage in your day. It starts, it shouts, and it keeps forwarding your
traffic. If you would rather it refused to start than run unbound, set
`CYGNOS_REQUIRE_BINDING=1`.

## Point Claude Code at it

In the **same terminal** where you'll run Claude Code:

```bash
export ANTHROPIC_BASE_URL=http://localhost:8788
```

Now use Claude Code exactly as normal. Your traffic flows through the proxy to
Anthropic untouched; Cygnos receives a usage event per request.

## Confirm it's working

- The proxy's **startup banner** is printed and the process is still running.
- The terminal running Claude Code has `ANTHROPIC_BASE_URL` set
  (`echo $ANTHROPIC_BASE_URL` → `http://localhost:8788`).
- Your **first event** appears in the Cygnos dashboard shortly after your first
  Claude Code message.

**Am I being captured right now?** Capture happens only when *both* are true:
the proxy process is running, **and** the terminal you launched Claude Code from
had `ANTHROPIC_BASE_URL` exported. A different terminal (or after `unset`) talks
to Anthropic directly with no capture.

## Stop / undo

```bash
unset ANTHROPIC_BASE_URL     # Claude Code instantly talks to Anthropic directly again
# then Ctrl-C the proxy process
```

This is the one-line escape hatch — see the transport note below.

## Troubleshooting

Run the proxy with `CYGNOS_CAPTURE_DEBUG=1` to log, per request, what it saw on
the wire (status, content-type, content-encoding, first bytes) and what it
extracted (model, tokens, status) — no prompt or response content is logged:

```bash
CYGNOS_CAPTURE_DEBUG=1 python -m cygnos_capture_proxy
```

If events show zero tokens, the debug log's `content_encoding` and `first_bytes`
lines are the place to look.

---

## Security & transport — read this once, honestly

- **The proxy sits in your request path.** While `ANTHROPIC_BASE_URL` points at
  it, your Claude Code traffic goes *through* this local process. If the process
  dies mid-request, that one in-flight request fails — the **one-line escape** is
  `unset ANTHROPIC_BASE_URL` (Claude Code then talks to Anthropic directly). Event
  emission is fully decoupled and fire-and-forget, so a Cygnos outage never
  affects your traffic.
- **Your Anthropic API key never reaches Cygnos.** It passes straight through to
  Anthropic. Cygnos receives only a one-way **hashed fingerprint** (16 hex chars)
  so you can tell keys apart — never the key itself.
- **Your prompts and responses never leave your machine.** This proxy reads a
  prompt only to forward it to Anthropic, and the response is never parsed for
  text at all. Cygnos receives a one-way SHA-256 hash of the prompt and a
  content-free risk verdict — PII reported by category name ("email"), never the
  value; sensitive terms reported as a count, never the terms. This is enforced
  in code: the proxy refuses to transmit any event carrying content.
