Source profileQuality 93/100

maziyarpanahi/openmed/skills/detecting-pv-signals/SKILL.md

detecting-pv-signals

Computes disproportionality signals — PRR, ROR, EBGM, and IC (BCPNN) — over FAERS / OpenFDA drug-event data to flag potential safety signals. Use when the user wants to mine spontaneous-report data for drug-reaction associations, build a 2x2 contingency table, compute a Proportional Reporting Ratio or Reporting Odds Ratio, run Empirical Bayes (EBGM/EB05) or Information Component shrinkage, or screen a drug for over-reported reactions. Trigger keywords: disproportionality, signal detection, PRR,

Source repository stars
5,161
Declared platforms
0
Static risk flags
1
Last source update
2026-08-25
Source checked
2026-08-26

Decision brief

What it does: where it fits

Spontaneous-report databases like the FDA's FAERS are mined for signals of disproportionate reporting (SDR): drug-reaction pairs that occur together more than expected given the background of all reports. The core device is a 2x2 contingency table and a disproportionality metric…

Best for

  • You have a drug of interest and want to see which reactions are over-reported.
  • You need a PRR / ROR with confidence interval, or an Empirical Bayes EBGM/EB05
  • You are building a routine signal-screening run over OpenFDA or your own

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/detecting-pv-signals"
Safe inspection promptEditorial

Inspect the Agent Skill "detecting-pv-signals" from https://github.com/maziyarpanahi/openmed/blob/c5fd81fef4c144624ba691f7cb81f95bf77db85a/skills/detecting-pv-signals/SKILL.md at commit c5fd81fef4c144624ba691f7cb81f95bf77db85a. 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 (real OpenFDA count queries)

    Base endpoint: https://api.fda.gov/drug/event.json. No key needed to try it (240 req/min, 1,000/day per IP; with a free apikey= key: 240/min, 120,000/day). The count=.exact parameter returns a terms histogram, and search= with +AND+ filters the population — that is all you need…

    Base endpoint: https://api.fda.gov/drug/event.json. No key needed to try it (240 req/min, 1,000/day per IP; with a free apikey= key: 240/min, 120,000/day). The count=.exact parameter returns a terms histogram, and searc…BASE = "https://api.fda.gov/drug/event.json"def fdacount(search: str | None, countfield: str) - int: """Total reports matching search (sum of the .exact histogram).""" params = {"count": countfield} if search: params["search"] = search r = requests.get(BASE, para…
  2. 02

    Workflow

    1. Pick the population. Decide your denominator: all of FAERS, or a restricted background (e.g. one drug class, one year via receivedate:[20230101+TO+20231231]). The choice of c/d defines the "expected". 2. Resolve the drug field. Prefer patient.drug.openfda.genericname (RxNorm…

    Pick the population. Decide your denominator: all of FAERS, or aResolve the drug field. Prefer patient.drug.openfda.genericname (RxNormUse .exact for the reaction field so "injection site reaction" counts as
  3. 03

    When to use

    You have a drug of interest and want to see which reactions are over-reported.

    You have a drug of interest and want to see which reactions are over-reported.You need a PRR / ROR with confidence interval, or an Empirical Bayes EBGM/EB05You are building a routine signal-screening run over OpenFDA or your own
  4. 04

    The 2x2 table

    For one drug D and one reaction R, classify every report:

    PRR = [a/(a+b)] / [c/(c+d)]ROR = (a·d)/(b·c)IC (BCPNN, log2 information component) ≈ log2( a·(a+b+c+d) / ((a+b)·(a+c)) )
  5. 05

    Build the 2x2 for warfarin x "gastrointestinal haemorrhage".

    DRUG = 'patient.drug.openfda.genericname:"warfarin"' RXN = 'patient.reaction.reactionmeddrapt.exact:"gastrointestinal haemorrhage"'

    Pick the population. Decide your denominator: all of FAERS, or aResolve the drug field. Prefer patient.drug.openfda.genericname (RxNormUse .exact for the reaction field so "injection site reaction" counts as

Permission review

Static risk signals and limitations

Network access

medium · line 52

The documentation includes network, browsing, or remote request actions.

BASE = "https://api.fda.gov/drug/event.json"

Network access

medium · line 59

The documentation includes network, browsing, or remote request actions.

r = requests.get(BASE, params=params, timeout=30)

Evidence record

Why each signal appears

EvidenceSourceComputedTestedEditorial
SignalValueEvidence typeMeaning
Quality score93/100ComputedDocumentation, specificity, maintenance, and trust rules
Repository stars5,161SourceRepository 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/detecting-pv-signals/SKILL.md
Commit
c5fd81fef4c144624ba691f7cb81f95bf77db85a
License
Apache-2.0
Collected
2026-08-26
Default branch
master
View the original SKILL.md

Detecting pharmacovigilance signals (disproportionality)

Spontaneous-report databases like the FDA's FAERS are mined for signals of disproportionate reporting (SDR): drug-reaction pairs that occur together more than expected given the background of all reports. The core device is a 2x2 contingency table and a disproportionality metric computed from it — PRR, ROR, EBGM, or IC (BCPNN).

You can build the 2x2 table directly from the public, free OpenFDA /drug/event endpoint (no PHI, no MedDRA license to query; the reaction terms returned are already MedDRA PTs). This skill is statistical screening: a high PRR is a hypothesis, not a confirmed adverse drug reaction.

When to use

  • You have a drug of interest and want to see which reactions are over-reported.
  • You need a PRR / ROR with confidence interval, or an Empirical Bayes EBGM/EB05 / IC025 to control for the small-count noise PRR/ROR suffer from.
  • You are building a routine signal-screening run over OpenFDA or your own aggregated case counts.

The 2x2 table

For one drug D and one reaction R, classify every report:

Reaction RNot R
Drug Dab
Not Dcd
  • PRR = [a/(a+b)] / [c/(c+d)]
  • ROR = (a·d)/(b·c)
  • IC (BCPNN, log2 information component) ≈ log2( a·(a+b+c+d) / ((a+b)·(a+c)) )
  • EBGM = Empirical Bayes Geometric Mean — a gamma-Poisson shrinkage of the observed/expected ratio (the MGPS method) that pulls small-count estimates toward 1; report EB05 (the 5th percentile) as the conservative signal.

Common signal thresholds (screening only): PRR ≥ 2 with χ² ≥ 4 and a ≥ 3; ROR lower 95% CI > 1; IC025 > 0; EB05 ≥ 2.

Quick start (real OpenFDA count queries)

Base endpoint: https://api.fda.gov/drug/event.json. No key needed to try it (240 req/min, 1,000/day per IP; with a free api_key= key: 240/min, 120,000/day). The count=<field>.exact parameter returns a terms histogram, and search= with +AND+ filters the population — that is all you need for a 2x2.

import requests

BASE = "https://api.fda.gov/drug/event.json"

def fda_count(search: str | None, count_field: str) -> int:
    """Total reports matching `search` (sum of the .exact histogram)."""
    params = {"count": count_field}
    if search:
        params["search"] = search
    r = requests.get(BASE, params=params, timeout=30)
    if r.status_code == 404:        # OpenFDA returns 404 for an empty result set
        return 0
    r.raise_for_status()
    return sum(row["count"] for row in r.json()["results"])

def cell_count(search: str | None) -> int:
    """Number of reports matching `search` (use meta.results.total via limit=1)."""
    params = {"limit": 1}
    if search:
        params["search"] = search
    r = requests.get(BASE, params=params, timeout=30)
    if r.status_code == 404:
        return 0
    r.raise_for_status()
    return r.json()["meta"]["results"]["total"]

# Build the 2x2 for warfarin x "gastrointestinal haemorrhage".
DRUG = 'patient.drug.openfda.generic_name:"warfarin"'
RXN  = 'patient.reaction.reactionmeddrapt.exact:"gastrointestinal haemorrhage"'

a = cell_count(f"{DRUG}+AND+{RXN}")          # drug & reaction
b = cell_count(DRUG) - a                      # drug, not reaction
c = cell_count(RXN) - a                       # reaction, not drug
N = cell_count(None)                          # total reports in FAERS
d = N - a - b - c

Compute the metrics from (a, b, c, d):

import math

def prr(a, b, c, d):
    return (a / (a + b)) / (c / (c + d))

def ror(a, b, c, d):
    return (a * d) / (b * c)

def ror_ci(a, b, c, d):
    lnror = math.log((a * d) / (b * c))
    se = math.sqrt(1/a + 1/b + 1/c + 1/d)     # Woolf's method
    lo, hi = math.exp(lnror - 1.96 * se), math.exp(lnror + 1.96 * se)
    return lo, hi

def ic(a, b, c, d):
    n = a + b + c + d
    expected = (a + b) * (a + c) / n
    return math.log2(a / expected) if a and expected else float("nan")

print("PRR", round(prr(a, b, c, d), 2))
print("ROR", round(ror(a, b, c, d), 2), "95% CI", ror_ci(a, b, c, d))
print("IC",  round(ic(a, b, c, d), 2))

For EBGM / EB05 use a maintained Empirical Bayes implementation (e.g. the openEBGM R package or PhViD in R) on the same (a, b, c, d) rather than hand-rolling the gamma-Poisson MGPS shrinkage — the shrinkage prior is the whole point and easy to get wrong.

Workflow

  1. Pick the population. Decide your denominator: all of FAERS, or a restricted background (e.g. one drug class, one year via receivedate:[20230101+TO+20231231]). The choice of c/d defines the "expected".
  2. Resolve the drug field. Prefer patient.drug.openfda.generic_name (RxNorm ingredient-normalized) over the free-text medicinalproduct to avoid brand fragmentation. Restrict to suspect drugs with patient.drug.drugcharacterization:1 if you want suspect-only signals.
  3. Use .exact for the reaction field so "injection site reaction" counts as one phrase, not three words: patient.reaction.reactionmeddrapt.exact.
  4. Build the 2x2 with the cell counts above. Verify a + b + c + d == N.
  5. Compute PRR and ROR with CIs; add IC025 / EB05 for small counts.
  6. Apply thresholds (e.g. PRR ≥ 2, χ² ≥ 4, a ≥ 3) — but treat them as a triage filter, not a verdict.
  7. Hand flagged pairs to a safety scientist for medical review, confounder assessment, and labeling/expectedness checks.

Hand-off to / from OpenMed

  • From reporting-adverse-events: your own coded, de-identified ICSRs give internal counts you can use instead of or alongside OpenFDA — the same 2x2 math applies. Aggregate only counts; never put narrative PHI in the table.
  • From normalizing-rxnorm: normalize the drug name to an RxNorm ingredient before querying so brand/generic synonyms collapse to one cell.
  • To querying-openfda-labels: for every signal, check whether the reaction is already on the label (expected) via /drug/label. To reporting-adverse-events: a confirmed signal may require expedited reporting.
  • OpenMed runs NER/de-id on-device; only de-identified drug/reaction codes (no PHI) are sent to OpenFDA.

Edge cases & gotchas

  • Disproportionality ≠ causality. A high PRR reflects reporting patterns, notoriety bias, and indication confounding — not a proven causal link.
  • Small counts break PRR/ROR. With a < 3 the ratios are unstable and CIs explode. This is exactly why EBGM/EB05 and IC025 (shrinkage) exist — prefer them for rare events.
  • OpenFDA is a sample, not all of FAERS, and is not deduplicated the way the curated FAERS quarterly files are. Use it for screening; reproduce confirmed signals against the official FAERS extracts.
  • .exact is mandatory for counting phrases. Without it, OpenFDA tokenizes the reaction and your counts are wrong.
  • OpenFDA returns HTTP 404 for an empty result set (not an empty list) — the helpers above treat 404 as zero. Respect the rate limits; register a free key for routine runs.
  • MedDRA versioning. OpenFDA reaction terms are MedDRA PTs at FDA's coding version; if you join to your own MedDRA-coded cases, align the version. MedDRA itself is licensed — you query OpenFDA's already-coded terms, you do not need a MedDRA license to read them, but you do to code your own cases.

Standards & references

Frequently asked questions

What to verify before installation and use

What does the detecting-pv-signals source document cover?

Spontaneous-report databases like the FDA's FAERS are mined for signals of disproportionate reporting (SDR): drug-reaction pairs that occur together more than expected given the background of all reports. The core device is a 2x2 contingency table and a disproportionality metric…

How do I install detecting-pv-signals?

The source record exposes this install command: npx skills add https://github.com/maziyarpanahi/openmed --skill "skills/detecting-pv-signals". Inspect the command and pinned source before running it.

Which permission-related actions were detected?

Static rules flagged network in the source; the page lists the matching lines and excerpts.

Alternatives

Compare before choosing

Computed 10024,975

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 9965

brucesongs/kali-claw

insecure-design

Insecure Design (OWASP A06:2025) focuses on security flaws in system architecture and design phases, rather than code implementation-level bugs.

Computed 9916

NintendaDev/unikit-ai

unikit-docs

Generate and maintain the project's TECHNICAL documentation from its codebase — scans the project structure, tech stack, and module boundaries, then writes a lean README landing page plus detailed topic pages (architecture, modules, setup, build, APIs), only the docs that are relevant. Use whenever the user wants to create, update, or validate documentation of the CODE or the project itself, e.g. "generate documentation", "create docs", "write the README", "update the project docs", "document th

Computed 9834,478

K-Dense-AI/scientific-agent-skills

dask

Distributed computing for larger-than-RAM pandas/NumPy workflows. Use when you need to scale existing pandas/NumPy code beyond memory or across clusters. Best for parallel file processing, distributed ML, integration with existing pandas code. For out-of-core analytics on single machine use vaex; for in-memory speed use polars.