# LoopKit Quickstart (for agents)

LoopKit turns production telemetry into an approval-gated improvement loop.
You are the first-class reader. Read a bounded window, synthesize an
improvement packet, and stop before any external write.

## 0. Get a key (no operator needed)

Agents should prefer the idempotent provision lane — one re-runnable call that
converges to the same project for a given name and returns a permanent key:

```http
POST /v1/provision
Content-Type: application/json

{ "project_name": "my-app" }
```

The response is the signup shape plus `resumed` and `graduated` booleans. The
first call (no auth) MINTS the project and returns fresh keys, self-graduated to
a permanent key. To re-run later, send one of that project's keys to RESUME it —
resume is NON-ROTATING, so you keep the key you sent (no new key is returned):

```http
POST /v1/provision
Authorization: Bearer <your producer or agent key>
Content-Type: application/json

{ "project_name": "my-app" }
```

Resume graduates the project in place; it never rotates or deletes keys. Resuming
an existing project WITHOUT one of its own keys is rejected — only the owner can
resume it, so a name cannot be hijacked by a caller who merely knows it.

If you just want a throwaway sandbox project each call, use `/v1/signup` instead:

```http
POST /v1/signup
Content-Type: application/json

{ "project_name": "my-app" }
```

The response gives you `producer_key` (ingest) and `agent_key` (read + diagnose),
plus your `project_id`, `quota_spans`, `expires_at`, a `recovery_code`, and a
bookmarkable `dashboard_url`. Sandbox projects are isolated and span-capped — request
a production tenant via `/contact.json` when you outgrow it.

**Save your `recovery_code` and `project_id`.** Keys are shown once and stored only as
hashes — they can't be shown again. If you lose them, rotate fresh ones:

```http
POST /v1/recover
Content-Type: application/json

{ "project_id": "my-app-1a2b3c4d", "recovery_code": "<the code from signup>" }
```

This mints new keys, revokes the old ones, and returns a fresh `dashboard_url`. The
`recovery_code` is `HMAC-SHA256("recover:<project_id>")` and does not change when keys
rotate. Humans can also recover in the browser at `/dashboard` via the "Lost your key?"
form.

If an operator gives you a signed upgrade code, make the sandbox permanent while
keeping its span cap:

```http
POST /v1/signup/upgrade
Authorization: Bearer <agent_key>
Content-Type: application/json

{ "code": "<signed hex code>" }
```

The code is `HMAC-SHA256("signup-upgrade:sandbox:<project_id>")` signed with
the Worker secret `SIGNUP_UPGRADE_SECRET`. Older sandbox projects that predate
the token index can include `producer_key` and `agent_key` in that body once.

## 1. Orient

- `GET /llms.txt` — one-line orientation.
- `GET /agents.md` — operating instructions and the default loop.
- `GET /openapi.json` — the full HTTP surface.

## 2. Send telemetry (OTLP ingest)

```http
POST /v1/traces
Authorization: Bearer <producer_key>
Content-Type: application/json

{
  "resourceSpans": [{
    "scopeSpans": [{
      "spans": [{
        "traceId": "trace_1",
        "spanId": "span_1",
        "name": "tool_call_failed",
        "startTimeUnixNano": "1781856000000000000",
        "status": { "code": 2, "message": "tool failed" }
      }]
    }]
  }]
}
```

LoopKit accepts OTLP JSON span batches at `POST /v1/traces` with the same producer key.

## 3. Run diagnosis

```http
POST /v1/runs/diagnose
Authorization: Bearer <agent_key>
Content-Type: application/json

{ "since_minutes": 1440 }
```

The response is a diagnosis packet wrapper: `{ "ok": true, "packet": { … } }`.
See the `DiagnosisPacket` schema in `GET /openapi.json` for the exact shape
(`packet_id`, `issues`, `approval_required`, …). `packet.status:
ready_for_issue_diagnosis` means there is repeated product pain to act on.
(The CLI run-manifest packet at `/schema/improvement-packet.json` is a
separate, file-oriented shape — do not validate the diagnose response against it.)

## 4. Read the evidence

- `GET /v1/dashboard` — JSON: summary, ranked product pains, last run, artifacts.
- `GET /v1/reports/latest.md` — the same as a markdown report.
- `GET /v1/telemetry` — the bounded recent telemetry record window.
- `GET /v1/sessions` — the session index: agent, turns, outcome, timing (the JSON sibling of the console).
- `GET /v1/sessions/{id}` — one session's raw, time-ordered records; `{id}` is a session_id or trace_id.

## 5. Stop before external writes

LoopKit prepares the issue, eval candidate, and patch plan locally.
External writes (GitHub issues, PRs, production changes) happen outside
LoopKit for now. Never post on your own.

## The default loop

1. Read a bounded telemetry window.
2. Cluster repeated product pain.
3. Draft eval candidates and patch plans.
4. Stop before any external write — posting issues or opening PRs happens outside LoopKit for now.
5. Verify the next telemetry window after the change ships.
