CoreLabel Documentation

Everything you need to annotate your data at scale.

Platform overview

CoreLabel Datum is an async data annotation pipeline. You upload a dataset, the platform pre-labels it with AI, routes low-confidence items to human reviewers, runs quality checks, and delivers a structured export.

The pipeline runs entirely in the background — submit a job and come back when it's done. You never label in Datum itself: human annotators work in Label Studio (files and agent trajectories) or Robotix (robot recordings), and Datum is the orchestration layer between your raw data and your annotation output.

RL-trajectory projects — robot recordings and agent runs — skip the file pipeline and become episodes instead. See Robotics projects and Agent projects.

Quickstart

1
Create a project — go to Projects → New project. Pick a data type (image, video, text, audio, structured, or RL trajectory) and give it a name.
2
Upload your data — go to Upload. Drag your files into the drop zone, or connect an existing S3/GCS bucket.
3
Submit a job — after upload completes you'll land on New Job with your data pre-filled. Select your project and hit Submit.
4
Monitor progress — watch the job move through pipeline stages on the Jobs page. The progress bar and status update in real time.
5
Download results — when status shows Completed, click ↓ Data to download your annotated dataset.
First time? Start with 10–50 files to validate the output format before running your full dataset.
RL-trajectory projects take a different route. Steps 2–5 above are the AI pre-labeling pipeline, which cannot read a recording or an agent trace. Neither kind uses Upload or New job — data is added from the project itself and becomes an episode. A robot project uses Add data (see Robotics projects); an agent project uses + Add trajectories (see Agent projects).

Projects

A Project groups jobs that share the same data type and label schema. Create one project per annotation task — for example, one for "product images" and a separate one for "customer reviews".

Data types

TypeSupported filesAI models used
Imagejpg, jpeg, png, webp, tiff, bmpGrounding DINO + SigLIP 2
Videomp4, mov, avi, mkv, webmX-CLIP (whole-clip classification)
Texttxt, csv, jsonl, json, pdf, docxspaCy + BART + DeBERTa
Audiowav, mp3, flac, ogg, m4aWhisper + classifier
Structuredcsv, json, jsonl, parquet, arrowCustom model
RL trajectory — robotROS bag, MCAP, RLDS, LeRobot, HDF5, video + tableNone — annotated in Robotix
RL trajectory — agentjsonl or json, one trace per line; harness output (.traj, .eval, .zip)Optional AI step-flagging when sent for labeling

You cannot change the data type after a project is created. If you need a different type, create a new project.

Uploading data

Go to Upload and drag files into the drop zone, or click to browse. Files upload directly to secure object storage — the backend never proxies your bytes, so large files are fast.

File-type validation

The allowed extensions depend on the data type you select. Rejected files show a ✗ icon and are skipped.

Progress tracking

Each file shows its own status icon: ⏳ uploading → ✓ done or ✗ failed. The overall progress bar updates as files complete. When all files finish, you're automatically redirected to New Job with the storage prefix pre-filled.

Uploaded files that are never turned into a job are automatically deleted after 7 days.

Robotics and agent projects are deliberately absent from this page's project list. Both become episodes rather than job input, so they are added from the project instead — see Robotics projects and Agent projects.

Cloud connector

Instead of uploading files, you can link an existing cloud bucket. CoreLabel reads data in-place — your files never leave your storage. Only annotation outputs are written back to CoreLabel's storage.

AWS S3

  1. Switch to the Cloud Connector tab on the Upload page.
  2. Select AWS S3 and enter your bucket name.
  3. Enter an Access Key ID and Secret Access Key for an IAM user with s3:ListBucket and s3:GetObject permissions on that bucket.
  4. Click Verify connection and wait for the status to turn green.

Google Cloud Storage

  1. Select Google Cloud Storage and enter your bucket name.
  2. Paste the full JSON contents of a service account key file. The service account needs the Storage Object Viewer IAM role.
  3. Click Verify connection.
Credentials are encrypted with AES-256 (Fernet) before being stored. They are only decrypted when a Celery worker needs to access your bucket.

Verification

Verification lists your bucket to confirm access and counts the files. This typically takes 5–30 seconds. The connector must be in verified status before you can create a job with it.

Jobs & pipeline

A Job is one annotation run. It takes a dataset and a project, then moves through the following pipeline stages automatically.

Pipeline stages

StageWhat happens
IngestingFiles are indexed; item count confirmed
QueuedWaiting for an AI worker slot
Pre-labelingAI model generates candidate labels for each item
Awaiting decisionAI is done; a quote for the uncertain items is waiting on you
AnnotatingPurchased items are with human annotators
QA reviewQuality checks run; IAA score calculated
AssemblingExport file and quality report built
CompletedOutput ready to download
FailedPipeline error — check the audit log
Quota exceededThe monthly pre-label allowance ran out before the job could run

Human review routing

Items where the AI confidence score falls below your project’s threshold (default 0.75) are escalated for human review. This happens on every plan — a plan decides how much AI pre-labeling you get, never whether an uncertain item is allowed to be seen.

Escalated items are never discarded. They are either sold to you as a lot and routed to annotators, or the job finishes with the AI label and the item is reported as unreviewed. Which of those happened is visible per item on Prelabel review.

IAA score

Inter-Annotator Agreement (IAA) measures how consistently two raters labelled the same items — the AI pre-label against a human annotation, or a human against the senior reviewer who re-checked their work. It ranges from 0.0 (no agreement) to 1.0 (perfect agreement).

It is Cohen's κ for classification and mean IoU for detection; the job tells you which, because the two are not comparable to each other. Where tasks went to a senior reviewer as well, a three-rater Fleiss' κ is also recorded.

A dash is not a zero. A job nobody reviewed has no agreement to measure, so IAA is blank rather than 0.00 — a zero would read as total disagreement. For those jobs we show AI confidence instead: the model's own certainty about its labels, which is not evidence that the labels are right. Until 2026-09-20 that confidence figure was itself shown in the IAA column.
ScoreInterpretation
≥ 0.80Excellent — label guidelines are clear
0.60 – 0.79Acceptable — review ambiguous cases
< 0.60Low — revisit your label definitions before proceeding

If IAA is consistently low, consider adding more examples to your label guidelines or reducing the number of label classes.

Robotics projects

A project whose data type is RL trajectory and whose pillar is robot works differently from every other project, because its data is a recording rather than a pile of files. It has no Upload step, no jobs, and no AI pre-labeling — a recording becomes an episode, and the episode is what gets annotated.

Adding data

Open the project and use + Add data. Everything arrives through the one page:

SourceWhat to give it
Upload a fileA ROS bag, an MCAP recording, an RLDS or LeRobot dataset, or an HDF5 session, dropped straight in
Hugging FaceA public dataset repo id, optionally a sub-path and episode index
Linked bucketNot available for robotics yet — the importers read an uploaded object

Formats

FormatAccepted asNotes
ROS bag.bag, or a ROS 2 bag directory zippedA bare .db3 is one SQLite file from inside a bag and cannot be read without its metadata.yaml. It is refused with that explanation.
MCAPA standalone .mcapFrom Foxglove, or taken out of its ROS 2 bag folder — it carries its own schemas. ROS 2, ROS 1, protobuf and JSON channels are read; a channel in another encoding is skipped and named in the imports table. A recording cut off mid-write is imported up to the cut, and the table says so.
RLDSA .zip of a TensorFlow Datasets directoryHow Open X-Embodiment and DROID ship: features.json, dataset_info.json and .tfrecord shards. You may upload only some shards; an episode in a missing shard is refused naming the file it needs. You must give the control rate — see below.
LeRobot.zip / .tar.gz, or a Hugging Face repov2.0, v2.1 and v3.0 are read. An unknown version is refused rather than guessed at.
HDF5.h5 / .hdf5REASSEMBLE-style, with a robot_state group. Force/torque traces import at full rate.
Video + tableAn .mp4 zipped with a .csv/.parquetFor rigs on neither ROS nor LeRobot. You must name the timestamp column and its unit — see below.

The format is detected, not declared

You are not asked to pick one. The file extension does not settle it — a .zip carries a LeRobot dataset and a ROS 2 bag directory alike — so the contents are read after the upload lands, and the result appears in the imports table marked detected.

An archive matching two formats is refused naming both rather than resolved by picking one. Guessing wrong would not produce a failed import; it would produce a successful one holding the wrong data under a name that looks right. If you know better than the probe, set the format explicitly under Advanced.

Video + table: name the clock

A table of numbers does not say what its timestamps mean. 1.5, 1500 and 1757000000 are all plausible readings of the same instant — seconds, milliseconds, or a Unix epoch — so you are asked which column holds the time and what unit it is in, under Uploading a video with a CSV? on the Add data page.

This is asked rather than guessed because guessing does not fail. The wrong unit shifts every annotation against the video by a constant, and the result looks entirely reasonable until somebody trusts it.

Rows must be in time order, and text columns are dropped rather than converted — a coerced text column becomes numbers an annotator reads as sensor dropout.

RLDS: give the control rate

RLDS stores the order of an episode's steps and nothing about their timing — no timestamps, no frame rate. So the signals and the camera frames have no clock until you supply one: under Uploading an RLDS dataset? on the Add data page, give the rate the robot was controlled at (DROID: 15 Hz). Camera frames are encoded into a video at that rate, frame for frame.

This is asked rather than guessed for the same reason as the video + table clock: a wrong rate does not fail. It stretches or squeezes the whole episode by a constant factor and every annotation still looks plausible. The episode records the rate as declared, so it is never mistaken for a measured one.

Steps' boolean flags (is_first, is_last) and very wide features such as a 512-number language embedding are not imported as signals. They are listed on the episode rather than dropped silently. The episode's language instruction becomes its task.

Several recordings in one upload

An upload holding several bags or MCAP files imports the one at the episode or recording index you give (counting from 0), and the imports table shows which of how many it read. Upload the others separately, or re-import with a different index.

Define your objects first

Shape tasks are built from the project's object ontology. A project with no objects defined produces an episode with nothing to annotate on — the import succeeds and no studio task appears. Add at least one object on the project page before importing.

Only terms of kind object become labels an annotator can draw. Materials and affordances are vocabulary: a box drawn around “graspable” would record a property as though it were a physical thing.

Why there are no jobs

Jobs exist to run AI pre-labeling over individual files and route the uncertain ones to human review. That pipeline cannot read a recording, so robotics projects do not offer jobs at all — there is no quota consumed, and no purchase gate. Human annotation happens in Robotix, below.

Agent projects

An agent project holds trajectories: recorded runs of an AI agent, one tool call per step. Each becomes an episode you can replay step by step, score, and send to human annotators who judge every step. Create one with data type RL trajectory and kind Agent — the kind defaults to Robot, so choose it deliberately.

Adding trajectories

Use + Add trajectories on the project page. Upload and New job do not list agent projects: their pipeline would read a trace as plain text and it would never become an episode. The page takes a .jsonl file (one trajectory per line) or a .json array — including conversations logged straight from the OpenAI or Anthropic APIs, OpenTelemetry exports, and the files agent harnesses leave behind: τ-bench and τ²-bench results, SWE-agent .traj, Inspect AI .eval logs, OpenHands event streams, and OpenAI Agents SDK trace exports. A harness’s own verdict (reward, score, expected actions) is kept as a hidden answer key and never shown to annotators. A bad line is listed with its reason and does not stop the rest.

Tick Score each trajectory to run the four scoring reports: tool & API schema, multi-agent handoffs, long-horizon memory, and efficiency. A report that has nothing to measure shows a dash, never a zero.

The file formats

One .jsonl line per trajectory, or a .json array. Any of them may be zstd-compressed (.zst) — the server decompresses it — and a single file may mix all of these shapes. Each line is recognised by what it contains, not by a name you give it.

FormatA line looks likeUse it whenWhat Datum gets from it
Generated record {"id", "ingest": {"framework", "raw_trace"}, "ground_truth"} You have an answer key — the shape our own reference dataset uses The steps, plus the ground truth that lets all four reports score it
Framework trace {"framework": "langchain", "raw_trace": {…}} You exported straight from the tool that ran the agent Converted for you. otel (spans), langchain (intermediate_steps), crewai (tasks_output), autogpt (steps), raw
Pre-shaped steps {"steps": [{"step_index", "state", "action", "outcome"}]} You control the exporter and would rather map the fields yourself Nothing to convert — it is already Datum's own shape. See What an annotator sees below for the fields worth filling
OpenAI chat messages {"messages": [… {"role": "assistant", "tool_calls": […]}, {"role": "tool", …}]} You logged the conversation from an OpenAI-compatible API (OpenAI, vLLM, LiteLLM, OpenRouter…) One step per tool call, matched to its reply by id; parallel calls become sibling steps. What the agent says to the user is a step too — a hallucinated result is often said rather than done. The user’s messages and any reasoning are shown above each call
Anthropic messages {"messages": [… {"role": "assistant", "content": [{"type": "tool_use", …}]}, …]} You logged a Claude conversation The same, from tool_use / tool_result blocks. Thinking, and any text written before a call, is shown as that call’s reasoning — even when one response was logged as several messages
OpenTelemetry {"resourceSpans": […]} — an OTLP JSON export Your agent is instrumented (Pydantic AI, LangGraph via OpenInference, Arize Phoenix, Langfuse…) Tool spans become steps; the model spans around them supply the reasoning, the arguments and the final reply. One episode per trace, or per conversation where the trace declares one — and a trace split across lines of an export is read as one. A tool that failed shows its error
Node graph {"nodes": [… "parent_id" …], "terminal_paths": […]} A simulator or benchmark harness that explores alternatives One episode per terminal path. oracle_steps becomes the efficiency baseline; per-node verdicts become the episode's answer key

A line that matches none of these is refused on its own, with the reason and the line number, while the rest of the file still loads. A conversation carrying both OpenAI and Anthropic markers is refused too, rather than read half wrong.

The otel name under framework trace reads a simplified span list, not a real OpenTelemetry export — for those, upload the OTLP JSON itself.

What an annotator sees

Each step is shown as one turn: who acted, then what they were answering and thinking, then the call and what came back. Whatever format you upload, these are the fields it is read from — fill them in pre-shaped steps to get the most out of labeling:

FieldShown as
state.agentThe actor on the turn. In a multi-agent trace this is what lets an annotator judge a handoff; without it every step reads “agent”
state.userA user: line — the message the step is answering
state.reasoningA thinking: line, shortened to about 600 characters. A step is often only wrong in the light of it
action.tool, action.paramsThe call
outcome.result, outcome.errorWhat came back (→), or the failure (✗)

AutoGPT’s thoughts and a node graph’s thought are shown the same way. The AI flagger reads exactly what the annotator reads, so on traces with reasoning it sees that too — its measured numbers come from traces without reasoning.

Node graphs in more detail

Each terminal path becomes its own episode — one coherent run an annotator can read top to bottom. Flattening the whole tree into one list instead would interleave branches, and a retry from a different branch would read as the agent repeating itself. A node on two paths therefore appears in both episodes, and the path id is part of the episode's reference.

What else comes across:

  • task.prompt becomes the goal on every step, and oracle_steps the efficiency baseline.
  • state_delta becomes what a step established. Nothing invents what a later step needed, so memory recall stays unmeasured rather than guessed.
  • Per-node annotation labels and violations are kept as the episode's answer key: scored against later, never shown to an annotator, and never translated into Datum's own labels. Their words are not our words, and the overlap is a guess.
  • No tool schema is built from allowed_tools: it lists names without parameters, and the scorer compares parameter keys exactly — so a schema built from it would mark almost every real call wrong.

Sending for labeling

Send N for labeling — on the project’s episode list or under the Add trajectories results — sends them as one Label Studio project, one task per trajectory, so an annotator works a single queue. Trajectories already sent are left out. A whole trajectory is always one task, never one task per step, because a wasted retry only looks wasteful beside the step it repeats.

Step labels

LabelMeaning
correctA reasonable step that did what it should
wrong toolA different tool was the right one
wrong paramsRight tool, wrong or malformed arguments
redundant retryRepeats an earlier step without changing anything
hallucinated resultActs on something the tool never returned
unsafe actionIrreversible or beyond the stated goal
needs reviewFlagged by a model; not a verdict — an annotator replaces it

Links between steps record a handoff to another agent, a delegation, or a step that recalls a fact established earlier.

AI step-flagging (optional)

Tick Flag suspicious steps with AI first when sending, and a model marks the steps worth a look before an annotator opens them:

  • It marks steps needs review with a note saying why, and deliberately never names the fault. Measured against known-flawed traces, 93% of the steps it flagged really were flawed — but it often named the wrong fault, so the label stays the annotator’s.
  • It finds under half of the flaws. It tells an annotator where to look first; it is never a reason to skip reading a step.
  • Where a trajectory has a tool & API schema report with a ground-truth schema, wrong tool and wrong params are labelled exactly instead, because that comparison cannot be wrong.
  • Handoff, delegation and recall links are drawn as well. They need no ground truth.
  • Everything arrives as a suggestion, never a saved label. Unflagged steps carry no mark, nothing is pre-filled as correct, and no confidence is filled in.
  • The most-flagged trajectories are placed first in the annotator’s queue.
  • It costs one pre-label unit per trajectory. If your allowance is used up, the trajectories are still sent — just without AI flags.

Checking your annotators

A golden task can be a whole trajectory with known per-step labels. It is mixed invisibly into labeling batches and scored when it comes back, which gives each annotator a skill profile. It is scored only on the steps the reference names; a named step left blank counts against the annotator. A golden is never saved as a real label on the episode it came from.

Robotix

Robot and sensor data is annotated in Robotix, a separate workspace built on CVAT. Image and text jobs stay in the standard pipeline; robotics episodes go to Robotix because they need tools the general annotation view does not have — 3D point clouds, synchronised video, and force traces sampled far faster than any camera.

Getting there

Open an episode from its project; its annotation tasks are listed under Annotate in Robotix, and each opens in a new tab.

You are signed in automatically. Open creates your studio account the first time, places you in your organization’s workspace and signs you in with your CoreLabel account — there is no separate studio password. Each Open uses a link that works once, for one minute, so if the studio ever shows its login page, go back and press Open again.

Reading the task list

Two markings on a row change what you should do with it.

What you seeWhat it means
Every kind returns its workIntervals key to a time span, shapes on frames key to a step, and shapes on video key to the instant that frame falls on. Camera tasks used to discard what you drew; they no longer do.
Not linked to a studio jobThe studio was still splitting the task up when it was created. The link still opens and annotations still would not come back. Re-import the episode rather than working on it.

Two kinds of task

An episode produces one task per sensor, and the tools you get depend on what that sensor records.

TaskYou drawTypical sensors
ShapesBoxes around objects, plus a grasp pose for anything that can be picked upCameras, endoscopes, ultrasound, lidar
IntervalsSpans of time on a signal trace — where an event starts and endsForce/torque, tactile pads

Object names in a shapes task come from your project’s ontology. Add a term there and it appears as a label; only physical objects are drawable, so categories like “graspable” stay as properties rather than things you can box.

Interval labels

Interval tasks share one vocabulary, so a span means the same thing whoever recorded it.

LabelMeans
contactThe tool is touching the environment
slipThe grasped object is slipping
force_spikeForce exceeded the safety limit
grip_engageThe gripper closed on the object
insertionA part is entering its mating feature
jamMotion is blocked while force keeps building

Mark each span with how sure you are — certain, probable or unsure. That rating is stored with the annotation and used when the data is scored, so an honest “unsure” is worth more than a confident guess.

Suggested spans

Some intervals are already drawn when you open a task. These are automatic suggestions, not answers: they are detected from the force trace and stay marked as suggestions until you accept them. Nothing counts as labelled until a person confirms it. Adjust the edges, correct the label, or delete a span that is wrong — the detector is right roughly twice as often as chance, which makes it a useful starting point and not something to trust unchecked.

Reading a force trace

Two things are worth checking before you label anything.

Whether the trace is compensated. The calibration panel shows which calibration produced the numbers on screen. An uncompensated channel can carry a steady offset of around 14 N from the weight of the tool itself — enough to look like sustained contact when the arm is simply holding still.

Where the timing comes from. The timeline draws camera frames as ticks rather than bars, because a 30 Hz camera has thirty instants per second and nothing in between. If a lane is flagged as being on a different clock, treat its alignment with the force trace as approximate.

On a tactile pad, hatched cells are dead taxels — no reading at all. They are not zero, and a contact that appears to stop at a hatched cell has not necessarily stopped.

Video tasks

Boxes drawn on a camera task are saved back. They are recorded against the instant the frame falls on rather than a step number, because a camera task is timed by the video’s own measured frame rate and the episode it belongs to may have no steps at all — a LeRobot import carries video and sensor traces but nothing step-shaped.

One thing camera tasks still do not get is a shape-quality score. That number is the studio’s comparison against a ground-truth job, and a camera task has none; it reads as not measured rather than as a zero.

Saving

Save in the studio as you normally would. Annotations return to CoreLabel automatically and quality is measured on arrival, so there is no separate submit step. Saving repeatedly is safe: each save replaces the previous one for that task rather than adding duplicates.

Quota

Each data item in a job consumes one AI pre-label. So does each agent trajectory sent with AI step-flagging ticked — one unit per trajectory regardless of length, charged only if the model actually runs. Human labeling is bought per batch and is never counted against quota. Usage is tracked per calendar month (UTC), resets on the 1st, and does not roll over.

Check current usage on the Quota page. Quota is reserved upfront when you submit a job; if the job fails it is not automatically refunded.

On Free, hitting the limit is a hard stop — job submission returns a quota-exceeded error (HTTP 429). On a paid plan the job proceeds and bills as overage, but only up to the spend cap you set, which starts at $0.

Plans

A plan is a monthly AI pre-label allowance and nothing else. Every export format, webhook and integration is available on every plan; there is no feature a higher plan unlocks.

PlanPriceIncluded pre-labels / monthOver the allowance
Free$01,000Hard stop
Medium$99/mo10,000Billed per 1,000, up to your cap
Advanced$500/mo75,000Billed per 1,000, up to your cap
Your overage cap defaults to $0 on every account, so a paid plan never bills more than its monthly price until you raise it deliberately.

Human labeling

A plan buys AI capacity. Human labeling is bought per batch, after the AI has run, so you decide with the confidence numbers in front of you rather than in advance.

When pre-labeling finishes, a self-serve job pauses at Awaiting decision with a quote covering exactly the items that fell below your threshold. Price depends on data type and how complex the work is; complexity is set by CoreLabel, not chosen at checkout.

Your three options

  • Accept — those items, and only those, go to human annotators. The job then continues through QA and export.
  • Decline — the job completes now with AI labels. Nothing is billed.
  • Do nothing — the quote expires and the job completes exactly as if you had declined. A job never sits waiting indefinitely.

A quote freezes its own numbers. If the price list changes between you seeing a quote and accepting it, you pay what you were shown.

Projects run as a managed engagement by CoreLabel skip this step: labeling is covered by the engagement, so there is nothing to approve.

Billing

Go to Billing to upgrade your plan. Payments are processed securely through Stripe — CoreLabel never stores your card details.

After a successful payment your plan updates immediately; you don't need to log out or refresh. Downgrading to Free is immediate and self-service — there is no payment involved in moving to a $0 plan, so it needs no support ticket.

Export formats

When a job completes, click ↓ Data on the Jobs page to download the annotation export in your project's configured format — JSON, CSV, COCO, YOLO, or Pascal VOC. The export contains every item with its labels, confidence scores, annotator metadata, and audit trail.

JSON structure

{
  "job_id": "abc123",
  "project": "Product images",
  "completed_at": "2026-06-28T12:00:00Z",
  "iaa_score": 0.87,
  "items": [
    {
      "id": "item_001",
      "source_key": "uploads/abc123/cat.jpg",
      "labels": [
        { "class": "cat", "confidence": 0.94, "bbox": [10, 20, 200, 180] }
      ],
      "reviewer": "human",
      "annotated_at": "2026-06-28T11:55:00Z"
    }
  ]
}

Other formats

COCO, YOLO, and Pascal VOC export formats are available on Scale and Enterprise plans. Custom schema export is available on Enterprise. Select the format when creating the project.