Label your logs

Your inference logs are a dataset waiting to be labeled. Here you collect them, train a small labeler, and label them on your own machine , the raw content never leaves your environment. This is the private alternative to Capture, which sends content to build the dataset for you.

The trick is that the model doing the labeling is one you trained (from a synthetic set, so nothing real is sent to train it), and it runs locally, in the browser, or in Node on Dawn (the native WebGPU backend), which is fast on a server with a GPU and still works on CPU without one.

Step 1 · Log your calls locally

collect → a task-tagged dataset on your box

Wrap any model call with tap, or log a pair with capture. It appends to a local JSONL-per-task store (default ./gerbil-data/<task>.jsonl). Nothing is sent anywhere.

collect.ts
import { capture, tap, configureCapture } from "@tryhamster/gerbil/tune";
configureCapture({ dir: "./gerbil-data" }); // local files (default)
// configureCapture({ sink: (row) => db.insert(row) }); // or your own store
// Wrap a call you already make — returns its result untouched, captures I/O:
const reply = await tap(
{ task: "support-triage", input: ticket.body },
() => openai.chat.completions.create({ /* ... */ }),
);
// Or log a pair directly (when you already have both sides):
await capture("support-triage", { input: ticket.body, output: reply });

tap pulls the output text from the result automatically (OpenAI / Anthropic / AI SDK shapes, or a string); pass extract to override. You now have a growing, task-tagged file of the inputs you want labeled.

Step 2 · Train your labeler on Tune

describe → a tiny classifier, yours to download

Go to the Tune surface, pick Describe the task, and hit the ★ Train an on-device labeler template. Describe your categories, a frontier teacher generates a synthetic labeling set (no real data of yours is sent), trains a small classifier, and you download it. Pin the label set with the output schema so it always returns a clean label:

task-description.txt
Label each input with exactly one category from:
billing, bug, feature-request, other. Reply with only the category.
output-schema.json
{
"type": "object",
"properties": {
"label": { "enum": ["billing", "bug", "feature-request", "other"] }
},
"required": ["label"]
}

You get back a native model (e.g. your-org/support-triage) that the Gerbil engine loads directly.

Step 3 · Label your logs on your own machine

run local → labeled rows, nothing sent

createLabeler loads your tuned model and enforces your label set (retrying JSON extraction under the hood). In Node this runs on Dawn, point it at a GPU server for speed, or let it fall back to CPU. Your raw inputs never leave the process.

label.ts
import { createLabeler, dataset } from "@tryhamster/gerbil/tune";
const labeler = await createLabeler({
model: "your-org/support-triage", // the labeler you just trained
labels: ["billing", "bug", "feature-request", "other"],
});
// Label one:
await labeler("My card was charged twice"); // → { label: "billing" }
// Or label a batch you collected in Step 1, writing the labels straight into a
// new task's dataset — all on your machine:
const inputs = (await dataset("support-triage").rows()).map((r) => r.input);
await labeler.labelInto("support-triage-labeled", inputs);
await labeler.dispose();

The same runs in the browser (WebGPU) if you'd rather label client-side. Then dataset("support-triage-labeled").toJSONL() gives you a ready-to-train file.

Step 4 · Use the labeled data

own it → train a specialist, or keep it

You now have { input, label } pairs built without your raw data ever leaving your environment. Feed them wherever you like, or upload just the labeled pairs (optionally redacted) to Tune to train a stronger specialist on real, labeled examples.

When to use this vs. Capture

 Label your logsCapture
Who labelsA model you trained, run locallyYou tag at the call-site; Gerbil stores it
Raw content leaves?Never, labeling is on your machineYes (optional on-device redaction)
Best whenData can't leave your environmentYou want the dataset built + hosted for you

See Capture for the hosted path, and Tune for training details.