target-prioritization ยท git:20260520.59814e1 ยท 2026-05-20 ยท sha256 da10eb786ba49277

target-prioritization git:20260520.59814e1A

Immutable. This exact content is served forever at /api/v1/blob/da10eb786ba49277.

---
name: target-prioritization
description: Prioritize drug targets from a ranked gene list (e.g., scRNA-seq DE output) by orchestrating parallel API queries against UniProt, OpenTargets, and PubMed, then re-ranking by a composite score combining protein localization, druggability, disease genetics, and research maturity. Use whenever the user wants to filter, triage, prioritize, or "do due diligence" on a list of candidate genes for drug discovery, especially after a DE / DEG analysis when they say things like "which of these should I follow up on", "filter for druggable targets", "make a target dossier", "rank these for tractability", "annotate these genes for druggability", or "build a target report". Trigger even when the user says just "filter these candidate genes" or hands over a CSV from a DE pipeline.
metadata: {"openclaw":{"requires":{"bins":["python3","curl"]},"emoji":"๐ŸŽฏ"},"version":"0.2.0"}
---

# Target Prioritization

A multi-source drug-target due-diligence pipeline for ranked gene lists.

## When this skill triggers

The user has a list of candidate genes (typically from a DE / DEG / scRNA-seq
analysis) and wants a per-gene dossier across multiple evidence dimensions
plus a composite re-ranking. The DE statistical rank is just the entry
point; the final priority is informed by protein biology, genetics,
druggability, and research maturity.

Common input shapes:
- A CSV with a `gene` column (DE output like `expression_table_pass_either_1s.csv`)
- A plain-text gene list (one symbol per line)
- A list of symbols inline in the user's message

## Output

Three files inside `<output_dir>/`:
1. **`targets_report.md`** โ€” one section per gene, sorted by composite score, with a
   short LLM-written rationale and recommended next step
2. **`targets_summary.csv`** โ€” flat table for sorting/filtering in Excel/pandas
3. **`raw_data/<source>.json`** โ€” raw API responses (audit trail, reusable across
   future re-scorings)

## Pipeline

```
input gene list
   โ”‚
   โ–ผ
scripts/orchestrate.py
   โ”‚
   โ”œโ”€โ–บ fetch_uniprot.py        โ†’ protein localization, surface, MHC, coding
   โ”œโ”€โ–บ fetch_opentargets.py    โ†’ tractability, approved drugs, associated
   โ”‚                              diseases (subsumes GWAS Catalog via OT's
   โ”‚                              integrated genetics evidence)
   โ””โ”€โ–บ fetch_pubmed.py         โ†’ paper counts (total + focus_disease + cell_context)
   โ”‚
   โ–ผ
scripts/aggregate.py
   โ”‚
   โ–ผ
output_dir/
  โ”œโ”€ raw_data/*.json
  โ”œโ”€ targets_summary.csv       โ† composite-score-ranked
  โ””โ”€ targets_report.md         โ† Claude fills the rationale sections
```

## How to invoke

```bash
python3 ~/myagents/myskills/target-prioritization/scripts/orchestrate.py \
    --input <gene_list.csv_or_txt> \
    --output <output_dir> \
    [--gene-col gene] \
    [--top 50]
```

- `--input` accepts a CSV (with `--gene-col`, default `gene`), a `.txt`/`.tsv`,
  or any file where the first column has gene symbols. Skips header if first
  cell is `gene`/`symbol`/case-insensitive.
- `--top` limits the dossier to the top N input genes (default 50) โ€” input
  order is preserved up to that cut, then composite-score re-ranks within.

`orchestrate.py` runs the three fetchers in parallel (Python threads, since
all calls are I/O-bound). Each writes a self-contained JSON to
`<output_dir>/raw_data/<source>.json`. Then `aggregate.py` merges them,
computes the composite score using `weights.yaml`, writes
`targets_summary.csv`, and emits a `targets_report.md` skeleton with one
section per gene โ€” the **rationale and risks fields are left blank for
Claude to fill**.

## Composite score

Weights live in `weights.yaml` and can be overridden per-run with `--weights`.
Defaults aim for "find druggable, genetically supported targets with known
biology":

```
composite_score = w1 * druggability_score        (approved drugs, tractability, clin trials)
                + w2 * disease_genetics_score    (OpenTargets disease associations + focus-disease bonus)
                + w3 * tractability_bonus        (surface or secreted vs intracellular)
                + w4 * expression_score          (from input DE if present)
                + w5 * novelty_bonus             (favors moderately studied)
                - w6 * over_studied_penalty      (PubMed total > cap โ†’ diminishing returns)
```

Each component is normalized to [0, 1]. The composite is therefore
roughly in [-w7, sum(w1..w6)] and is min-max rescaled before reporting.
**Read `weights.yaml` for the current defaults.**

## Writing the rationale

After `aggregate.py` produces `targets_report.md` with blank rationale
slots, Claude reads the per-gene dossier rows and writes a 2-3 sentence
rationale per gene. Use the template in `prompts/rationale_template.md` โ€”
it specifies the structure (one line on the most compelling evidence, one
line on the main risk, one line on the suggested next experimental step).

For the top 5โ€“10 genes by composite score, also write a short executive
summary at the top of the report. Keep it factual and grounded in the
dossier data; do not hallucinate beyond what the JSONs contain.

## Data source notes

All free, no API key needed. Rate limits handled in fetchers:
- **UniProt REST** โ€” 100 req/sec, batched via `accession` query
- **OpenTargets GraphQL** โ€” generous, single endpoint; provides disease genetics signal via integrated `associatedDiseases`
- **PubMed E-utilities** โ€” 3 req/sec without key; fetchers respect this

For deeper API details and field mappings, see
`references/api_endpoints.md`.

## Retargeting the focus disease + cell context

The skill ships with an autoimmunity / T-cell default but is intentionally
disease-agnostic. Two edits switch the focus:

- `scripts/fetch_opentargets.py` and `scripts/aggregate.py` โ€” change
  `FOCUS_DISEASE_TERMS` to the lowercased substrings that should mark a
  drug or disease association as "in-scope" (e.g.
  `("cancer", "carcinoma", "lymphoma")` for oncology;
  `("alzheimer", "parkinson", "huntington", "als")` for neurodegeneration;
  `("diabetes", "obesity", "fatty liver", "nash")` for metabolic disease).
- `scripts/fetch_pubmed.py` โ€” adjust the `focus_disease` and
  `cell_context` queries in `CONTEXTS` (e.g.
  `"hepatocyte"`, `"neuron"`, `"macrophage"` instead of `"T cell"`).

No other code changes are needed; the CSV column names already use the
neutral `focus_disease_*` / `cell_context` prefixes.

## When NOT to use this skill

- Single-gene look-ups (overkill โ€” just ask Claude to web-search)
- Non-human genes (most APIs are human-only; fetchers will silently return empty)
- Pure literature review without target ambition โ€” use `scholar-deep-research` or `literature-review` instead

## Iteration tips

The pipeline is designed to be re-runnable cheaply:
- Raw JSON cache means re-scoring with different `weights.yaml` is a one-second `aggregate.py` rerun
- To add a new evidence source, add `scripts/fetch_<source>.py` that writes
  `raw_data/<source>.json` with the same `{gene: {fields}}` shape, then add
  a corresponding term in `aggregate.py::compute_composite_score`.