MCPInstall

bulk-classify

Sort many texts into your own categories without reading them, using a keyless HTTP API that returns a calibrated confidence per answer. Use when triaging, filtering, routing or bucketing more items than are worth putting in context — search results before you read them, log lines, tickets, files, diffs, past conversations. Triggers on "filter these", "which of these are relevant", "triage", "bucket", "route", "categorise", or any loop that would otherwise read N items to keep a few.

Installs
750
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://classifier.dev --skill bulk-classify
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads bulk-classify automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

Classify at scale without reading

classifier.dev assigns text to your categories. No key, no signup, no SDK. One HTTP call takes up to a thousand texts at a time and comes back in about a second, each with a confidence you can act on.

Data sharing and workspace usage

Synchronous classification text, labels, instructions and results are retained for training and operator review by default. Pass share_data: false in MCP arguments or the HTTP JSON body when the user has not chosen to contribute the data. The equivalent HTTP header is X-Classifier-Share-Data: false. Do not send confidential or personal information as training data. See https://classifier.dev/privacy for the current policy.

Public calls use anonymous limits. Workspace attribution and paid features require a workspace API key in the client's secure credential configuration; never put keys in this skill, chat, or committed configuration. Do not claim a connection is working until a real tool call succeeds.

When this is worth a network call

You are a language model. You can already classify any text you can see, for free. The question is whether you want this text in your context at all.

Reach for this when reading the input is the expensive part:

  • Filtering before reading. You have 40 search snippets and want the 6 worth opening. Classifying them yourself means pulling all 40 into context first, which is the cost you were trying to avoid. One call returns 40 labels and you read only the survivors.
  • Cascade pre-filter. Cheaply drop the obvious no's, then spend real reasoning on what is left.
  • Streams you would never read line by line. Log lines, error buckets, inbound tickets, changed files in a large diff, ten thousand URLs' titles.
  • Label-based routing. Use the fast tier to route texts into your categories. Model updates, fallback, and smart reasoning can change answers; neither tier guarantees identical results across calls.

Do not bother when you have a handful of items already in context, or the judgement needs reasoning about things the text does not state. Under about five items you have already paid the context cost, so just decide yourself.

Quickstart

One text, bare label back:

curl "https://classifier.dev/relevant,not+relevant/Redis+beats+Postgres+for+queues"
relevant

The same call as query parameters, when code is building the URL:

curl "https://classifier.dev/?labels=relevant,not+relevant&text=Redis+beats+Postgres+for+queues"
relevant

Many texts in one call. This is the path that matters:

curl https://classifier.dev -d '{
  "labels": ["relevant", "not relevant"],
  "inputs": ["first snippet", "second snippet", "third snippet"]
}'

Returns results in input order. Single-label results have {label, confidence, scores}. Confidence and scores can be null; check before comparing a threshold. Multi-label results use {labels: [...], scores: {...}} instead. Up to 1,000 texts per call; 400 news headlines measured at 650ms end to end. For more, fan out calls in parallel; the limit is 3,000 classifications a minute. Each result also names the model that answered it. At the batch level, modelsUsed lists every serving model and model is mixed when more than one model answered the batch.

From a shell

When the text is already in files, or the answer feeds another command, the CLI saves you writing the batching and the JSON:

npm i -g classifier-dev

classify bug,feature,praise < feedback.txt          # label<TAB>confidence<TAB>text, input order
classify relevant,"not relevant" --review 0.7 < snippets.txt   # only the unsure ones
classify db,web,ml --count < titles.txt             # a histogram instead of rows
classify a,b --json < items.txt | jq -c 'select(.confidence == null or .confidence < 0.8)'

It batches a thousand inputs per request, four requests at a time, and streams rows as they land, so | head on a large file returns at once. Retries 429 and 5xx with backoff. --help has the rest.

Reach for the HTTP API instead when the text is already in memory, when you need the full score map per item, or when you are inside a language runtime where one fetch is simpler than a subprocess.

Parameters

FieldNotes
labels2–100 categories. Required.
inputOne text; above 32,000 characters, default/explicit Jev uses paid Fast-only long context.
inputsUp to 1,000 texts in one call.
tierfast (default) or smart: re-asks low-confidence answers of a reasoning model.
instructionsExtra criteria — "judge only the service, ignore the food".
multiReturn every label that applies, with a score per label.
max_labelsCap on how many multi-label answers come back.
verbose=1On GET, returns JSON instead of a bare label.
textOn GET, the text as a query parameter: /?labels=a,b&text=.... input and q work too; classes and categories for labels.

Long context requires a workspace key backed by paid balance or an active paid subscription; signup credit and anonymous access do not qualify. Use POST with at most 250,000 original cl100k_base context tokens across inputs, 20 documents, 32 decisions and a 1 MB body. Price: $0.084/M original context tokens counted once across inputs, independent of dimensions and actual screening/final usage. Final Jev reads selected whole chunks in source order; eligible evidence may be omitted when the budget fills. usage.long_context discloses selection. No evidence returns 422 long_context_no_evidence without charge. Explicit model: "chunklaya" remains a separate legacy opt-in.

On GET every option goes in the query string, whichever form carries the labels and text; the two forms mix (/a,b?text=...). If a GET is malformed the error comes with usage: and try: — try is a URL built from what you sent that would have worked. Follow it rather than re-reading the docs.

Labels are read semantically, so name them in words: urgent bug classifies better than p0.

Confidence you can act on

The model is a decision model, not an LLM prompted to classify: it returns a calibrated probability for every label. Measured on 400 six-way emotion items, answers at confidence ≥ 0.9 were right 82% of the time; answers below 0.5 were right 29% of the time. So:

for text, r in zip(texts, results):
    if r["confidence"] is not None and r["confidence"] >= 0.8:
        act(r["label"])
    else:
        look_yourself(text)      # or send it through tier "smart"

tier: "smart" does that routing server-side: every single-label answer under 0.7 confidence is re-asked of a fast reasoning model and replaced, marked escalated: true, with usage.escalated telling you how many. Measured: four-way news 87.5% → 90.0% by re-asking 12% of items. It costs a few seconds per escalated item, so a batch on smart is slower in proportion to how uncertain it is. Escalated answers have confidence: null, scores: null, and unscored: the reasoning model does not return comparable probabilities. These answers belong in review when your workflow requires a confidence gate.

Many labels at once

To tag instead of sorting (an article against fifty topics, a ticket against every subsystem it touches), ask for every label that applies:

curl https://classifier.dev -d '{
  "input": "...",
  "labels": ["machine learning", "databases", "... up to 100 ..."],
  "multi": true,
  "max_labels": 10
}'

Results carry labels (an array, most likely first) plus scores, one probability per label. POST multi-label results omit the singular label and confidence keys. Labels at or above 0.7 are returned; use scores to pick your own threshold. On GET, add ?multi=1 and they come back one per line. Measured F1 0.887 on a seven-task set with recall 0.99, in ~200ms. The tier makes no difference here, so leave it on fast.

Two things that will bite you

1. Every call returns one of your labels, always. There is no "none of the above" unless you supply one. Text that fits nothing still gets confidently sorted into your best-matching category: "the weather is nice today" against bug / feature / praise must land in one of those categories. If "none of these" is a real outcome, add it as a label. Hoping for a low score does not create a missing category.

2. Confidence predicts accuracy, not fit. It tells you how likely the chosen label is right among your labels, which is exactly what you want for routing. It does not tell you whether the text belongs to any of them; see point 1. Scores express the model's choice among the labels you supplied. They do not validate the input or prove the choice is correct, so supply labels suitable for every kind of input your caller may send. Confidence and scores can be null when the provider returns none or the smart tier replaces the scored answer.

Recipe: filter search results before reading them

import json, urllib.request

def keep_relevant(question, snippets):
    body = json.dumps({
        "labels": ["relevant", "not relevant"],
        "inputs": snippets,                      # up to 1,000
        "instructions": (
            f"Relevant means it helps answer: {question}. "
            "Include background and contrasting alternatives."
        ),
    }).encode()
    req = urllib.request.Request(
        "https://classifier.dev",
        data=body,
        headers={
            "content-type": "application/json",
            "user-agent": "my-agent/1.0",
        },
    )
    results = json.load(urllib.request.urlopen(req))["results"]
    # A dropped item is invisible, so keep anything the model was unsure about.
    return [s for s, r in zip(snippets, results)
            if r["label"] == "relevant" or r["confidence"] is None
            or r["confidence"] < 0.8]

Then read only what comes back. The snippets you dropped never enter context.

Bias a filter toward keeping. You never learn what you lost, so recall matters more than precision here. The confidence gate above does that directly; "When in doubt, keep it" in the instructions also measurably helps.

Python's standard urllib, curl and Node fetch work without a custom User-Agent. A descriptive agent name is optional. For a JSON error, read code, action and retryable: a 403 can mean the free service detected an anonymous proxy network, which requires a funded workspace key. A 429 carries Retry-After. An HTML error is an edge/network failure; report its status and request ID rather than assuming classification ran.

Report a problem with classifier.dev

If classifier.dev itself returns a wrong result shape, contradicts its docs, or creates repeated integration friction, report that to the service instead of classifying the report as input. Read the live policy first:

GET https://classifier.dev/.well-known/agent-feedback.json

For a short report, send one category and one useful sentence. No key is needed:

curl https://classifier.dev/api/v1/observations -d '{
  "category": "docs_mismatch",
  "summary": "The documented response field was absent from POST /v1/classify.",
  "surface": "/v1/classify"
}'

Use POST /api/v1/feedback when you have reproduction steps or other evidence. It accepts the envelope and limits described by the discovery document. Both routes return a receipt; poll GET /api/v1/receipts/{id} to confirm it landed. Never include credentials, private input text, or unrelated user data in a report or its evidence.

Limits

Per IP per minute: 3,000 classifications on fast, 200 on smart; per day 20,000 and 2,000. A batch of 400 counts as 400. 429 when exceeded, with RateLimit-Limit on every response. Errors are JSON on POST, {"error": "...", "code": "..."}, and plain text on GET unless you add ?verbose=1 or send Accept: application/json.

Reference

  • GET / — full docs, plain text
  • GET /openapi.json — OpenAPI 3.1
  • GET /benchmark — measured accuracy, calibration, cost and latency

FAQ

What does the bulk-classify skill do?

Sort many texts into your own categories without reading them, using a keyless HTTP API that returns a calibrated confidence per answer. Use when triaging, filtering, routing or bucketing more items than are worth putting in context — search results before you read them, log lines, tickets, files, diffs, past conversations. Triggers on "filter these", "which of these are relevant", "triage", "bucket", "route", "categorise", or any loop that would otherwise read N items to keep a few.

How do I install bulk-classify?

Run npx skills add https://classifier.dev --skill bulk-classify in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/bulk-classify/ (personal) or .claude/skills/bulk-classify/ (project).

Which AI agents can use bulk-classify?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is bulk-classify safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains bulk-classify?

It is published by classifier.dev in classifier.dev. It has 750 recorded installs.

Popular backend & apis skills

View category →

find-skills

vercel-labs/skills

Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.

OfficialBackend & APIs4.1M installs

entra-app-registration

microsoft/azure-skills

Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance.

OfficialBackend & APIs566.7K installs

This skill should be used when the user wants to "write agent code", "build an agent with ADK", "add a tool", "create a callback", "define an agent", "use state management" — in a project that needs ADK (Agent Development Kit) API patterns and code examples. It provides a quick reference for agent types, tool definitions, orchestration patterns, callbacks, state management, the graph Workflow API, and reference recipes to study. Do NOT use for scaffolding (use google-agents-cli-scaffold) or deployment (use google-agents-cli-deploy).

Backend & APIs514.8K installs

embedded-captions

heygen-com/hyperframes

Add captions or subtitles to an existing single-subject talking-head video without editing the footage. Use for plain verbatim captions, cinematic captions embedded behind the subject, VFX captions, “炸/特效/酷炫字幕,” or a named identity from the 35-style catalog. Route by visual identity, not by backend engine. The quiet anchor rail is the default; embed every word only when the user explicitly wants a fully cinematic treatment. The workflow runs locally end to end, including transcription and subject matting; split multi-shot footage before applying it.

Backend & APIs453.3K installs

entra-agent-id

microsoft/azure-skills

Provision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token exchange (fmipath, OBO, cross-tenant) including the Microsoft Entra SDK for AgentID sidecar. USE FOR: Agent Identity Blueprint, BlueprintPrincipal, agent OAuth, fmipath token exchange, agent OBO, Workload Identity Federation for agents, polyglot agent auth, Microsoft.Identity.Web.AgentIdentities. DO NOT USE FOR: standard Entra app registration (use entra-app-registration), Microsoft Foundry agent authoring (use microsoft-foundry).

OfficialBackend & APIs336.6K installs

neon

neondatabase/agent-skills

Overview of Neon, a complete set of cloud backend primitives around Lakebase Postgres: Auth, Object Storage, Functions, the AI Gateway, and Realtime. Start here to choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or MCP server, and follow the branch-first workflow. Use when building an app or backend on Neon, or when "Neon" or "Lakebase Postgres" is mentioned. Child skill neon-postgres wins for an existing DATABASEURL, SQL, schema, inspect, or search. Child skill neon-auth wins for login, users, sessions, identity routing, and Managed Better Auth setup. Child skill neon-realtime wins for live queries in reactive apps and agents. Also use for object storage, S3, buckets, serverless functions, function triggers, cron, AI gateway, LLM calls, realtime, logs, Loki, Grafana, observability, postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.

Backend & APIs237.1K installs