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
maziyarpanahi/openmed/skills/detecting-pv-signals/SKILL.md
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,
Decision brief
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…
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/maziyarpanahi/openmed --skill "skills/detecting-pv-signals"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
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…
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…
You have a drug of interest and want to see which reactions are over-reported.
For one drug D and one reaction R, classify every report:
DRUG = 'patient.drug.openfda.genericname:"warfarin"' RXN = 'patient.reaction.reactionmeddrapt.exact:"gastrointestinal haemorrhage"'
Permission review
The documentation includes network, browsing, or remote request actions.
BASE = "https://api.fda.gov/drug/event.json"The documentation includes network, browsing, or remote request actions.
r = requests.get(BASE, params=params, timeout=30)Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 93/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 5,161 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
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.
For one drug D and one reaction R, classify every report:
| Reaction R | Not R | |
|---|---|---|
| Drug D | a | b |
| Not D | c | d |
Common signal thresholds (screening only): PRR ≥ 2 with χ² ≥ 4 and a ≥ 3; ROR lower 95% CI > 1; IC025 > 0; EB05 ≥ 2.
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.
receivedate:[20230101+TO+20231231]). The choice of c/d defines the
"expected".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..exact for the reaction field so "injection site reaction" counts as
one phrase, not three words: patient.reaction.reactionmeddrapt.exact.a + b + c + d == N.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.normalizing-rxnorm: normalize the drug name to an RxNorm ingredient
before querying so brand/generic synonyms collapse to one cell.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.a < 3 the ratios are unstable and CIs
explode. This is exactly why EBGM/EB05 and IC025 (shrinkage) exist —
prefer them for rare events..exact is mandatory for counting phrases. Without it, OpenFDA tokenizes
the reaction and your counts are wrong.count, .exact, search AND/OR): https://open.fda.gov/apis/query-syntax/Frequently asked questions
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…
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.
Static rules flagged network in the source; the page lists the matching lines and excerpts.
Alternatives
alirezarezvani/claude-skills
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
brucesongs/kali-claw
Insecure Design (OWASP A06:2025) focuses on security flaws in system architecture and design phases, rather than code implementation-level bugs.
NintendaDev/unikit-ai
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
K-Dense-AI/scientific-agent-skills
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.