# Integration guide

End-to-end walkthrough: from "I have an AI pipeline" to "every decision flows through LoopDesk".

## 1. Inventory your decisions

List every place your pipeline produces an answer that ships to a user, an internal system, or a database. For each, write down:

* **Output type** — string, structured JSON, action (refund, ban, send-email)
* **Cost of being wrong** — financial, reputational, regulatory
* **Volume** — items per day
* **Current accuracy estimate** — even rough

Decisions with non-trivial cost-of-wrong belong in LoopDesk. The rest don't.

## 2. Create a project

One per use case. From `/projects`, create a project and set:

* **Name** — `support-replies-eu`, `invoice-tagging`, etc.
* **Auto threshold** — start at `0.95` (conservative)
* **Review threshold** — start at `0.70`
* **Escalate flags** — at minimum `["escalate", "legal", "high_value"]`
* **Guidelines** — one paragraph per rule, reviewer-facing

Copy the **project\_id** and generate an **API key** from the project page.

## 3. Wire up submission

In your pipeline, after the model produces a suggestion, POST it to the public API instead of shipping directly:

```ts
const res = await fetch("https://human-in-the-loop.cc/api/public/items", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": process.env.LOOPDESK_API_KEY!,
  },
  body: JSON.stringify({
    project_id: PROJECT_ID,
    input: { message: userMessage, user_id: userId },
    suggestion: aiReply,
    confidence: scoringResult.score,
    risk_flags: detectRiskFlags(userMessage, aiReply),
    metadata: { region: "eu", model: "gpt-5.4" },
  }),
});

const { id, status, decision } = await res.json();
```

The response is synchronous. `status` is one of:

* `auto_approved` — `decision` is populated, ship immediately
* `queued` — `decision` is `null`, wait for the webhook
* `escalated` — `decision` is `null`, wait for the webhook
* `rejected` — `decision` is null, do not ship

## 4. Build the risk-flag detector

This is where a lot of value lives. A simple, fast classifier (or regex set) that adds flags to every item:

```ts
function detectRiskFlags(input: string, suggestion: string): string[] {
  const flags: string[] = [];
  if (containsEmail(input) || containsPhone(input)) flags.push("pii");
  if (mentionsRefund(suggestion)) flags.push("high_value");
  if (mentionsLegalAdvice(suggestion)) flags.push("legal");
  if (input.length > 2000) flags.push("long_input");
  return flags;
}
```

You can iterate on the detector independently of the model. Cheap wins live here.

## 5. Receive decisions via webhook

Add an endpoint your side that LoopDesk will call when a queued/escalated item is decided. Configure the URL and secret on the project page.

```ts
// your service
import { createHmac, timingSafeEqual } from "crypto";

app.post("/loopdesk-webhook", async (req, res) => {
  const sig = req.headers["x-webhook-signature"] as string;
  const raw = req.rawBody; // capture raw body, not parsed JSON
  const expected = createHmac("sha256", process.env.LOOPDESK_WEBHOOK_SECRET!)
    .update(raw)
    .digest("hex");

  if (!sig || !timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
    return res.status(401).end();
  }

  const { event, item_id, status, decision } = JSON.parse(raw);
  if (event === "item.decided" && status === "approved") {
    await shipToUser(item_id, decision);
  }
  res.status(200).end();
});
```

## 6. Add reviewers

Invite reviewers (they connect with a Solana wallet — wallet-only auth). Assign each one to the relevant project's reviewer pool. Walk them through the [Reviewer handbook](/hitl-docs/guides/reviewer-handbook.md).

## 7. Run for a week, then tune

Resist the urge to tune thresholds on day one. Let real traffic flow for at least a few hundred items, then open `/analytics`:

* If override rate is high in the auto-approved band → lower `auto_threshold` until the queue catches those items
* If the queue is overwhelming → check whether overrides cluster in a narrow band; if not, raise `auto_threshold` cautiously
* If a flag never fires → remove it
* If a flag always fires → it's not a flag, it's a constant; remove it and route differently

See [Tuning thresholds](/hitl-docs/guides/tuning-thresholds.md).

## 8. Close the loop

Once a week, open `/learnings`, cluster recent corrections by reason, and ship one of:

* A new or revised project guideline
* A prompt update (with new few-shot examples from learnings)
* A new risk flag (with a corresponding pipeline detector)
* A retraining batch (export learnings as JSONL)

If you do this monthly instead of weekly, the queue grows. Weekly is the cadence.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hitl-01.gitbook.io/hitl-docs/guides/integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
