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.
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:
Label each input with exactly one category from:billing, bug, feature-request, other. Reply with only the category.{ "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.
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 logs | Capture | |
|---|---|---|
| Who labels | A model you trained, run locally | You tag at the call-site; Gerbil stores it |
| Raw content leaves? | Never, labeling is on your machine | Yes (optional on-device redaction) |
| Best when | Data can't leave your environment | You want the dataset built + hosted for you |
See Capture for the hosted path, and Tune for training details.