Source profileQuality 90/100

maziyarpanahi/openmed/skills/batch-processing-clinical-text/SKILL.md

batch-processing-clinical-text

Run large-scale batch NER, PII extraction, or de-identification over many clinical notes on-device with OpenMed, with sharding, checkpointing, resumability, and append-only JSONL output. Use when the user needs to process a corpus or folder of notes, de-identify a dataset, run NER over thousands of documents, build a resumable batch pipeline, or stream results to JSONL without holding everything in memory. Covers process_batch / BatchProcessor / BatchItem / BatchResult, the operation= selector (

Source repository stars
4,847
Declared platforms
0
Static risk flags
0
Last source update
2026-08-04
Source checked
2026-08-04

Decision brief

What it does—and where it fits

openmed.processing runs OpenMed over many documents efficiently, with progress tracking, per-item error isolation, and streaming. It runs fully on-device: the corpus, the model, and the output never leave the host. This skill shows a resumable runner — sharded, checkpointed, app…

Best for

  • For corpora, folders, or datasets — anything beyond a handful of notes. For a single note, just call openmed.analyzetext / deidentify directly (extracting-clinical-entities, deidentifying-clinical-text). For an always-o…

Not for

  • Tasks that require unconfirmed production actions or broad system permissions.
  • Environments where the pinned source and install steps cannot be inspected.

Compatibility matrix

Platform support, with evidence labels

PlatformStatusEvidenceWhat to check
CodexNot declaredNo explicit evidencePortability before use
Claude CodeNot declaredNo explicit evidencePortability before use
CursorNot declaredNo explicit evidencePortability before use
Gemini CLINot declaredNo explicit evidencePortability before use
Open the compatibility checker

Installation

Inspect first. Install second.

The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

Source-detected install commandSource
npx skills add https://github.com/maziyarpanahi/openmed --skill "skills/batch-processing-clinical-text"
Safe inspection promptEditorial

Inspect the Agent Skill "batch-processing-clinical-text" from https://github.com/maziyarpanahi/openmed/blob/e412ae8f3b04ae79b13663d34a422efc22109a3a/skills/batch-processing-clinical-text/SKILL.md at commit e412ae8f3b04ae79b13663d34a422efc22109a3a. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

Workflow

What the source asks the agent to do

  1. 01

    Quick start

    processbatch(...) is a thin wrapper over BatchProcessor. Real signatures (openmed/processing/batch.py):

    processbatch(texts, modelname="diseasedetectionsuperclinical", ids=None, config=None, progresscallback=None, onprogress=None, kwargs) - BatchResultBatchProcessor(modelname=..., operation="analyzetext", batchsize=8, continueonerror=True, analyzekwargs)BatchItem(id, text, source=None, metadata=None)
  2. 02

    Workflow

    1. De-identify upstream if the corpus has PHI, or key everything by stable internal ids so logs/output never carry identifiers. 2. Pick the operation + model — one BatchProcessor per operation (analyzetext / extractpii / deidentify); reuse it across all items so the loader is sh…

    De-identify upstream if the corpus has PHI, or key everything by stablePick the operation + model — one BatchProcessor perShard the corpus into independent partitions writing to separate JSONL
  3. 03

    When to use this skill

    For corpora, folders, or datasets — anything beyond a handful of notes. For a single note, just call openmed.analyzetext / deidentify directly (extracting-clinical-entities, deidentifying-clinical-text). For an always-on HTTP service, see serving-openmed-rest-api.

    For corpora, folders, or datasets — anything beyond a handful of notes. For a single note, just call openmed.analyzetext / deidentify directly (extracting-clinical-entities, deidentifying-clinical-text). For an always-o…
  4. 04

    Choosing the operation

    python from openmed import BatchProcessor

    python from openmed import BatchProcessor
  5. 05

    NER (default)

    ner = BatchProcessor(modelname="diseasedetectionsuperclinical") operation="analyzetext"

    ner = BatchProcessor(modelname="diseasedetectionsuperclinical") operation="analyzetext"

Permission review

Static risk signals and limitations

No configured static risk pattern was detected

This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.

Evidence record

Why each signal appears

EvidenceSourceComputedTestedEditorial
SignalValueEvidence typeMeaning
Quality score90/100ComputedDocumentation, specificity, maintenance, and trust rules
Repository stars4,847SourceRepository attention, not individual Skill quality
Compatibility0 platformsSourceDeclared in the catalog source record
Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

Pinned source

Provenance and original SKILL.md

Repository
maziyarpanahi/openmed
Skill path
skills/batch-processing-clinical-text/SKILL.md
Commit
e412ae8f3b04ae79b13663d34a422efc22109a3a
License
Apache-2.0
Collected
2026-08-04
Default branch
master
View the original SKILL.md

Batch processing clinical text

openmed.processing runs OpenMed over many documents efficiently, with progress tracking, per-item error isolation, and streaming. It runs fully on-device: the corpus, the model, and the output never leave the host. This skill shows a resumable runner — sharded, checkpointed, append-only JSONL — that you can restart without reprocessing.

When to use this skill

For corpora, folders, or datasets — anything beyond a handful of notes. For a single note, just call openmed.analyze_text / deidentify directly (extracting-clinical-entities, deidentifying-clinical-text). For an always-on HTTP service, see serving-openmed-rest-api.

Quick start

from openmed import process_batch

texts = ["Patient has type 2 diabetes.", "No acute distress. BP 120/80."]
result = process_batch(texts, model_name="disease_detection_superclinical")

print(result.summary())          # PHI-safe counts + timing
print(result.successful_items, "/", result.total_items)
for item in result.get_successful_results():
    print(item.id, item.result.to_dict()["entities"])   # spans only; avoid raw text in logs

process_batch(...) is a thin wrapper over BatchProcessor. Real signatures (openmed/processing/batch.py):

  • process_batch(texts, model_name="disease_detection_superclinical", ids=None, config=None, progress_callback=None, on_progress=None, **kwargs) -> BatchResult
  • BatchProcessor(model_name=..., operation="analyze_text", batch_size=8, continue_on_error=True, **analyze_kwargs) with operation ∈ {"analyze_text", "extract_pii", "deidentify"}.
  • BatchItem(id, text, source=None, metadata=None)
  • BatchResult.items, .total_items, .successful_items, .failed_items, .success_rate, .average_processing_time, .summary(), .to_dict(), .get_successful_results(), .get_failed_results().
  • BatchItemResult.id, .result (a PredictionResult/DeidentificationResult), .error, .processing_time, .source, .success, .to_dict().

Choosing the operation

from openmed import BatchProcessor

# NER (default)
ner = BatchProcessor(model_name="disease_detection_superclinical")          # operation="analyze_text"
# Detect PHI spans
pii = BatchProcessor(operation="extract_pii", model_name="OpenMed/OpenMed-PII-SuperClinical-Small-44M-v1")
# De-identify (rewrites text)
deid = BatchProcessor(operation="deidentify", method="mask", confidence_threshold=0.7)

BatchProcessor reuses one model loader across items (and a cached privacy filter for PII ops), so a single processor over many texts is far cheaper than many one-off calls.

Streaming + PHI-safe progress

from openmed.processing import BatchProcessor, BatchProgress

proc = BatchProcessor(operation="deidentify", method="mask", batch_size=16)

def on_progress(p: BatchProgress) -> None:   # frozen record: completed/total/current_index/elapsed
    if p.completed % 500 == 0:
        print(f"{p.completed}/{p.total} ({p.elapsed:.1f}s)")   # NO PHI

for item in proc.iter_process(texts, ids=doc_ids, on_progress=on_progress):
    write_jsonl(item)   # one result at a time — constant memory for huge corpora

on_progress receives only counts/timing (never text), so it is safe to log. iter_process yields BatchItemResults without holding the whole corpus.

Workflow

  1. De-identify upstream if the corpus has PHI, or key everything by stable internal ids so logs/output never carry identifiers.
  2. Pick the operation + model — one BatchProcessor per operation (analyze_text / extract_pii / deidentify); reuse it across all items so the loader is shared.
  3. Shard the corpus into independent partitions writing to separate JSONL files; run shards as separate processes for parallelism.
  4. Stream with iter_process and append each BatchItemResult to JSONL (flush per item) — that append-only file is your checkpoint.
  5. Track progress with the PHI-safe on_progress callback (counts/timing only).
  6. Re-run to resume: skip ids already present in the output; with continue_on_error=True, failures are recorded, not raised.
  7. Reconcile via result.get_failed_results() / a failures pass, then hand JSONL to the downstream consumer.

A resumable batch runner

import json
from pathlib import Path
from openmed.processing import BatchProcessor

def run_resumable(texts, ids, out_path: Path, *, operation="deidentify", **kw):
    out_path.parent.mkdir(parents=True, exist_ok=True)
    # 1) checkpoint = ids already written (append-only JSONL is the source of truth)
    done = set()
    if out_path.exists():
        with out_path.open() as f:
            done = {json.loads(line)["id"] for line in f if line.strip()}
    todo = [(i, t) for i, t in zip(ids, texts) if i not in done]
    if not todo:
        return
    pending_ids, pending_texts = zip(*todo)

    proc = BatchProcessor(operation=operation, continue_on_error=True, **kw)
    # 2) append each result as it completes -> safe to kill/restart anytime
    with out_path.open("a") as f:
        for item in proc.iter_process(list(pending_texts), ids=list(pending_ids)):
            record = {"id": item.id, "ok": item.success,
                      "result": item.result.to_dict() if item.success else None,
                      "error": item.error}            # item.error is a message, keep PHI out
            f.write(json.dumps(record) + "\n")
            f.flush()

Re-running skips finished ids (continue_on_error=True keeps one bad doc from killing the run; failures are recorded, not raised). Shard a corpus by writing to out/shard_000.jsonl, shard_001.jsonl, … and run shards in separate processes.

Chunking long documents

BatchProcessor does not split single documents. For notes longer than the model's max sequence length, pre-split into sentences/windows (openmed.processing.sentences) — or for analyze_text, rely on built-in sentence handling — then re-stitch entities by adding the chunk offset back to each entity's start/end so spans point into the original document.

Hand-off to / from OpenMed

  • Per-item engine: each operation calls the same openmed.analyze_text / extract_pii / deidentify you'd call directly — same results, batched.
  • Downstream: JSONL feeds building-patient-timelines, etl-to-omop-cdm, and exporting-to-fhir. De-id JSONL feeds evaluating-with-leakage-gates.
  • Service vs batch: for request/response use serving-openmed-rest-api; for corpora use this batch path.

Edge cases & gotchas

  • No PHI in logs/JSONL keys. Use stable ids (BatchItem.id), offsets, and labels. BatchItemResult.error is a message — keep raw text out of inputs to exceptions you log.
  • continue_on_error=True is the default and recommended for corpora; check result.get_failed_results() afterward. Set False only when one failure should abort everything.
  • batch_size is a throughput dial, not correctness — tune to memory/CPU. Larger isn't always faster on CPU.
  • Append-only is the checkpoint. Don't buffer results in memory and write at the end; you lose progress on a crash. Append + flush per item.
  • process_files/process_directory read files for you and set BatchItem.source; unreadable files become failed items (not crashes) under continue_on_error.
  • Mixed languages: pass lang= per run for PII ops; don't run an English PII model across other languages (deidentifying-multilingual-text).

Standards & references

Alternatives

Compare before choosing

Computed 10023,781

alirezarezvani/claude-skills

app-store-optimization

App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist

Computed 10014,225

wanshuiyin/Auto-claude-code-research-in-sleep

citation-audit

Use it for operations and research tasks; the detail page covers purpose, installation, and practical steps.

Computed 1004,922

dotnet/skills

migrate-vstest-to-mtp

Migrates .NET test projects from VSTest to Microsoft.Testing.Platform (MTP). Use when user asks to "migrate to MTP", "switch from VSTest", "enable Microsoft.Testing.Platform", "use MTP runner", set OutputType=Exe only for test projects in Directory.Build.props, or mentions EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner. USE FOR: MTP behavioral differences vs VSTest (exit code 8, zero tests discovered, --ignore-exit-code, TESTINGPLATFORM_EXITCODE_IGNORE); centralizing

Computed 1002,504

aaron-he-zhu/aaron-marketing-skills

social-selling-planner

Use when the user asks to "set up my founder social-selling routine", "build a daily engagement block for target accounts", or "turn funding / hiring signals into selling plays"; produces the founder/seller daily operating block — a time-boxed engagement-block spec (substantive value-add comments on target-account posts, never a pitch), warm-touch-before-ask cadence rules, trigger-response plays consuming the social-pulse-monitor B2B trigger watchlist (funding / hiring / launch signals), and a q