opencode-bioresearcher 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +103 -0
- package/agents/bioresearcher-dr-worker.md +54 -0
- package/connector-meta.json +23 -0
- package/index.js +77 -0
- package/loader.js +3 -0
- package/package.json +42 -0
- package/skill-bundle.json +12 -0
- package/skills/bioresearcher-deep-research/SKILL.md +330 -0
- package/skills/bioresearcher-deep-research/references/analysis-methods.md +90 -0
- package/skills/bioresearcher-deep-research/references/article-literature.md +89 -0
- package/skills/bioresearcher-deep-research/references/best-practices.md +102 -0
- package/skills/bioresearcher-deep-research/references/citations.md +146 -0
- package/skills/bioresearcher-deep-research/references/clinical-trials.md +87 -0
- package/skills/bioresearcher-deep-research/references/diseases.md +94 -0
- package/skills/bioresearcher-deep-research/references/drugs.md +88 -0
- package/skills/bioresearcher-deep-research/references/ensembl-pdb.md +134 -0
- package/skills/bioresearcher-deep-research/references/functional-genomics.md +118 -0
- package/skills/bioresearcher-deep-research/references/genes.md +93 -0
- package/skills/bioresearcher-deep-research/references/optional-analysis.md +108 -0
- package/skills/bioresearcher-deep-research/references/patents.md +92 -0
- package/skills/bioresearcher-deep-research/references/rate-limiting-auth.md +95 -0
- package/skills/bioresearcher-deep-research/references/report-template.md +117 -0
- package/skills/bioresearcher-deep-research/references/tool-selection.md +142 -0
- package/skills/bioresearcher-deep-research/references/utility-config.md +116 -0
- package/skills/bioresearcher-deep-research/references/variants.md +109 -0
- package/skills/bioresearcher-deep-research/references/worker-protocol.md +110 -0
- package/skills/bioresearcher-deep-research/scripts/markdown-to-html.py +86 -0
- package/skills/bioresearcher-plot-making/SKILL.md +97 -0
- package/skills/bioresearcher-plot-making/references/literature-search-method-summary.md +163 -0
- package/skills/bioresearcher-plot-making/references/qa-gates-and-gotchas.md +156 -0
- package/skills/bioresearcher-plot-making/references/structural-biology-binder-visualization.md +206 -0
- package/skills/bioresearcher-plot-making/scripts/audit_figure_collisions.py +742 -0
- package/skills/bioresearcher-plot-making/scripts/audit_panel_alignment.py +935 -0
- package/skills/bioresearcher-plot-making/scripts/audit_pdf_text.py +152 -0
- package/skills/bioresearcher-plot-making/scripts/plot_helpers.py +177 -0
- package/skills/bioresearcher-pubmed-weekly/SKILL.md +223 -0
- package/skills/bioresearcher-pubmed-weekly/scripts/parse_updatefiles.py +272 -0
- package/skills/bioresearcher-pubmed-weekly/scripts/pubmed_weekly.py +493 -0
- package/skills/bioresearcher-python-setup-uv/SKILL.md +184 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Utility & Configuration Tools
|
|
2
|
+
|
|
3
|
+
Cross-cutting tools: `discover`, `batch_get`, and `biomcp_configure`.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`discover` resolves free text to typed entities; `batch_get` fetches many
|
|
8
|
+
entities in parallel with per-item failure isolation; `biomcp_configure` is
|
|
9
|
+
the unified inspect/configure surface for optional features (database, R
|
|
10
|
+
analysis, biowasm) and environment parameters.
|
|
11
|
+
|
|
12
|
+
## Tools
|
|
13
|
+
|
|
14
|
+
### discover
|
|
15
|
+
|
|
16
|
+
| Parameter | Type | Notes |
|
|
17
|
+
|-----------|------|-------|
|
|
18
|
+
| query | string (required) | Free text, e.g. "BRAF V600E", "lung cancer", "imatinib" |
|
|
19
|
+
|
|
20
|
+
Returns entities matching the concept with their types and IDs - the right
|
|
21
|
+
first call when a question's entity types are ambiguous.
|
|
22
|
+
|
|
23
|
+
### batch_get
|
|
24
|
+
|
|
25
|
+
| Parameter | Type | Notes |
|
|
26
|
+
|-----------|------|-------|
|
|
27
|
+
| inputs | array (required) | Items: `{entity, id, sections?}` where entity is one of `gene`, `variant`, `drug`, `disease`, `trial`, `article`, `patent` |
|
|
28
|
+
|
|
29
|
+
Fetches all inputs in parallel server-side; ONE failed item does not fail the
|
|
30
|
+
batch - the response carries per-item failure rows. Prefer this over N
|
|
31
|
+
sequential `*_get` calls when you already know the IDs.
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{"inputs": [
|
|
35
|
+
{"entity": "gene", "id": "BRAF", "sections": ["core", "druggability"]},
|
|
36
|
+
{"entity": "trial", "id": "NCT04280705", "sections": ["core"]},
|
|
37
|
+
{"entity": "article", "id": "21639808"},
|
|
38
|
+
{"entity": "drug", "id": "vemurafenib", "sections": ["safety"]}
|
|
39
|
+
]}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### biomcp_configure
|
|
43
|
+
|
|
44
|
+
| Parameter | Type | Notes |
|
|
45
|
+
|-----------|------|-------|
|
|
46
|
+
| action | `status` (default) / `set` / `reset` | status works with no other arguments |
|
|
47
|
+
| values | object, optional | For set: `{"<dotted file-param id>": value}` e.g. `{"features.analysis_biowasm.enabled": true}`; `null` removes a key; max 32 keys per call |
|
|
48
|
+
| target | string or array, optional | For reset: a feature id (`database`, `analysis_r`, `analysis_biowasm`) removes the section, or a list of dotted ids |
|
|
49
|
+
| filter | string, optional | For status: `file`, `env`, a feature id, or dotted-id prefix - returns detailed rows |
|
|
50
|
+
| dry_run | boolean, optional | Validate and diff without writing |
|
|
51
|
+
| confirm_sensitive | boolean, optional | Must be true when set/reset touches sensitive keys (connection targets, mirrors, credentials) - first attempts are refused by design |
|
|
52
|
+
|
|
53
|
+
Key behaviors:
|
|
54
|
+
|
|
55
|
+
- Calling with `{}` returns the status overview: per-feature running state,
|
|
56
|
+
config file health, conflicts, pending-restart flags, dependency
|
|
57
|
+
prerequisites.
|
|
58
|
+
- Feature groups and their env gates: `database` (DB_TYPE=mysql|sqlite),
|
|
59
|
+
`analysis_r` (ANALYSIS_R=1), `analysis_biowasm` (ANALYSIS_BIOWASM=1).
|
|
60
|
+
- REGISTRATION-TIME GATING: tool groups register at SERVER START only. After
|
|
61
|
+
enabling a feature (via env block or this tool's `set`, which writes
|
|
62
|
+
`.biomcp.json` in the server's working directory), the tools appear only
|
|
63
|
+
after a client RESTART - until then calls return `no_such_tool`. There is
|
|
64
|
+
no live activation.
|
|
65
|
+
- Environment-only parameters (API keys, proxy, security boundaries like
|
|
66
|
+
ANALYSIS_BIOWASM_DATA_DIR) are QUERY-ONLY here - the response explains how
|
|
67
|
+
to set them in the client env block; env values are masked (presence +
|
|
68
|
+
fingerprint).
|
|
69
|
+
- A `set` is refused (`cwd_refused`) when the server's working directory is
|
|
70
|
+
not a project root (e.g. cwd-less clients like Claude Desktop) - the error
|
|
71
|
+
carries a paste-ready env-block translation.
|
|
72
|
+
- `.biomcp.json` is loaded once at startup; env variables take precedence
|
|
73
|
+
over the file; `BIOMCP_PROJECT_CONFIG=0` disables file loading entirely.
|
|
74
|
+
|
|
75
|
+
## Worked examples
|
|
76
|
+
|
|
77
|
+
Overall status:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Enable SQLite database feature:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{"action": "set", "values": {"features.database.enabled": true,
|
|
87
|
+
"features.database.type": "sqlite",
|
|
88
|
+
"features.database.sqlite_path": ["data/geo.db"]}}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
(the first set of sensitive keys like sqlite_path is refused - re-send the
|
|
92
|
+
identical call with `"confirm_sensitive": true`)
|
|
93
|
+
|
|
94
|
+
Check a feature's parameters in detail:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{"action": "status", "filter": "features.analysis_r"}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Failure modes
|
|
101
|
+
|
|
102
|
+
| Symptom | Cause | Fix |
|
|
103
|
+
|---------|-------|-----|
|
|
104
|
+
| `no_such_tool` after enabling a feature | tools register at server start only | restart the client/session, then verify with `biomcp_configure` `{}` (`running_now`) |
|
|
105
|
+
| set refused: "sensitive" | sensitive key class requires confirmation | re-send identical call with `confirm_sensitive: true` |
|
|
106
|
+
| `cwd_refused` | server cwd is / or $HOME | use the client env block (error carries the translation) |
|
|
107
|
+
| batch_get item row contains `_error` | that single ID failed (typo, unknown ID) | fix the ID and re-request just that item; other items succeeded |
|
|
108
|
+
|
|
109
|
+
## Integration notes
|
|
110
|
+
|
|
111
|
+
- Smoke-test sequence for a fresh setup: `biomcp_configure` with `{}` ->
|
|
112
|
+
confirm expected features `running_now` -> one cheap domain call.
|
|
113
|
+
- `doctor` CLI complements this: `npx -y biomcp@1.1 doctor` (exit 0 = clear);
|
|
114
|
+
`--client opencode` emits a paste-ready client entry.
|
|
115
|
+
- Multi-entity literature pulls (e.g. 10 PMIDs from article_search) belong in
|
|
116
|
+
ONE `batch_get` call, not 10 article_get calls.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Variant Research
|
|
2
|
+
|
|
3
|
+
Variant search, annotation, oncology evidence, and trial cross-links via
|
|
4
|
+
`variant_search` / `variant_get` / `variant_oncokb` / `variant_trials`.
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
`variant_search` queries MyVariant.info with STRUCTURED parameters (gene +
|
|
9
|
+
protein change as separate fields - not compound free text); `variant_get`
|
|
10
|
+
returns per-variant annotation with sections; `variant_oncokb` adds precision
|
|
11
|
+
oncology evidence (token-gated); `variant_trials` links to clinical trials.
|
|
12
|
+
|
|
13
|
+
## Tools
|
|
14
|
+
|
|
15
|
+
### variant_search
|
|
16
|
+
|
|
17
|
+
| Parameter | Type | Notes |
|
|
18
|
+
|-----------|------|-------|
|
|
19
|
+
| query | string, optional | rsid ("rs113488022") or HGVS ("NM_004333.4:c.1799T>A"). Do NOT put compound text like "BRAF V600E" here |
|
|
20
|
+
| gene | string, optional | Gene symbol filter, e.g. "BRAF" - pair with hgvsp |
|
|
21
|
+
| hgvsp | string, optional | Protein change, e.g. "V600E" - pair with gene |
|
|
22
|
+
| hgvsc | string, optional | cDNA change |
|
|
23
|
+
| rsid | string, optional | dbSNP rsID |
|
|
24
|
+
| significance | enum, optional | `benign`, `likely_benign`, `pathogenic`, `likely_pathogenic`, `uncertain` (ClinVar) |
|
|
25
|
+
| consequence | string, optional | e.g. "missense", "synonymous" |
|
|
26
|
+
| max_frequency | number, optional | Max allele frequency 0-1 (gnomAD-style rarity filter) |
|
|
27
|
+
| min_cadd | number, optional | Minimum CADD score |
|
|
28
|
+
| limit | int 1-50, default 10 | Maximum results |
|
|
29
|
+
| offset | int >= 0, default 0 | Result offset |
|
|
30
|
+
|
|
31
|
+
### variant_get
|
|
32
|
+
|
|
33
|
+
| Parameter | Type | Notes |
|
|
34
|
+
|-----------|------|-------|
|
|
35
|
+
| id | string (required) | rsid, HGVS, or ClinVar ID |
|
|
36
|
+
| sections | enum array, optional | `core`, `frequency`, `predictions`, `clinical`, `alphagenome_scores`, `all`. Core (id, gene, rsid, significance) is ALWAYS returned at top level |
|
|
37
|
+
| limit | int 1-100, default 20 | Caps arrays within sections |
|
|
38
|
+
|
|
39
|
+
Note: `alphagenome_scores` is currently UNAVAILABLE - it returns an error stub
|
|
40
|
+
pending reimplementation. Request the other sections instead.
|
|
41
|
+
|
|
42
|
+
### variant_oncokb
|
|
43
|
+
|
|
44
|
+
| Parameter | Type | Notes |
|
|
45
|
+
|-----------|------|-------|
|
|
46
|
+
| gene | string (required) | Gene symbol, e.g. "BRAF", "EGFR" |
|
|
47
|
+
| protein_change | string (required) | e.g. "V600E", "L858R" |
|
|
48
|
+
|
|
49
|
+
REQUIRES the `ONCOKB_TOKEN` environment variable (register at oncokb.org).
|
|
50
|
+
Returns OncoKB precision-oncology levels of evidence, oncogenic status, and
|
|
51
|
+
therapeutics.
|
|
52
|
+
|
|
53
|
+
### variant_trials
|
|
54
|
+
|
|
55
|
+
| Parameter | Type | Notes |
|
|
56
|
+
|-----------|------|-------|
|
|
57
|
+
| variant | string (required) | rsID, HGVS, or variant ID |
|
|
58
|
+
|
|
59
|
+
## Worked examples
|
|
60
|
+
|
|
61
|
+
The canonical BRAF V600E lookup (structured, never free text):
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{"gene": "BRAF", "hgvsp": "V600E", "limit": 5}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Pathogenic missense variants in a gene, rarity-filtered:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{"gene": "TP53", "consequence": "missense",
|
|
71
|
+
"significance": "pathogenic", "max_frequency": 0.001, "limit": 20}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
By rsID directly:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{"query": "rs113488022"}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Deep annotation of one variant:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{"id": "rs113488022", "sections": ["frequency", "predictions", "clinical"]}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
OncoKB evidence (token present):
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{"gene": "EGFR", "protein_change": "L858R"}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Failure modes
|
|
93
|
+
|
|
94
|
+
| Symptom | Cause | Fix |
|
|
95
|
+
|---------|-------|-----|
|
|
96
|
+
| variant_oncokb error mentioning token | `ONCOKB_TOKEN` not set | register/request access at oncokb.org and set it in the client env block, or skip OncoKB and rely on `variant_get` clinical section |
|
|
97
|
+
| 0 hits for "BRAF V600E" passed as query | compound free text is not an rsid/HGVS | use `gene` + `hgvsp` as separate parameters (the tool also auto-splits a bare "GENE V600E" string, but explicit params are reliable) |
|
|
98
|
+
| alphagenome_scores error stub | section currently unavailable | request `frequency`/`predictions`/`clinical` instead |
|
|
99
|
+
| Empty results with many filters | over-constrained combination | relax filters one at a time (drop `min_cadd` first, then `max_frequency`) |
|
|
100
|
+
|
|
101
|
+
## Integration notes
|
|
102
|
+
|
|
103
|
+
- Chain: variant_search -> variant_get (detail) -> variant_oncokb (oncology
|
|
104
|
+
evidence, if token) -> variant_trials / trial_get (clinical relevance).
|
|
105
|
+
- For NOVEL variants (absent from databases) use `ensembl_consequence`
|
|
106
|
+
(VEP on demand) instead of variant_get - see references/ensembl-pdb.md.
|
|
107
|
+
- `discover(query="BRAF V600E")` resolves ambiguous variant text to typed
|
|
108
|
+
entities first when unsure.
|
|
109
|
+
- MyVariant is server-limited at 100 ms - no manual throttling.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Worker Protocol
|
|
2
|
+
|
|
3
|
+
The canonical contract for per-aspect research workers - both parallel
|
|
4
|
+
subagents and the sequential fallback in the main conversation.
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
Each worker owns exactly ONE research aspect of a TOPIC. It queries biomcp
|
|
9
|
+
tools, collects identifiers, and writes one markdown file under
|
|
10
|
+
`reports/<TOPIC>/`. Workers never re-delegate, never fabricate, and never fall
|
|
11
|
+
back to internal knowledge for facts. Workers also never interview the user -
|
|
12
|
+
clarification is exclusively the orchestrator's Step 1 (SKILL.md).
|
|
13
|
+
|
|
14
|
+
## Worker prompt template (orchestrator fills this in)
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
TOPIC: <TOPIC>
|
|
18
|
+
YOUR RESEARCH FOCUS: <RESEARCH-ASPECT>
|
|
19
|
+
DESCRIPTION: <ABSTRACT>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- ABSTRACT: <200 words describing the exact focus of the aspect and a list of
|
|
23
|
+
detailed research items to investigate.
|
|
24
|
+
- Tier B (generic subagent): the orchestrator should ALSO inline into the
|
|
25
|
+
prompt the Worker Rules below, the per-domain tool cheatsheet from
|
|
26
|
+
`references/tool-selection.md`, and the citation format summary from
|
|
27
|
+
`references/citations.md` - generic subagents may not have access to this
|
|
28
|
+
skill's files.
|
|
29
|
+
- Tier A (dedicated `bioresearcher-dr-worker` plugin subagent): the worker
|
|
30
|
+
reads this file plus `references/tool-selection.md` and
|
|
31
|
+
`references/citations.md` itself at startup (via
|
|
32
|
+
`${CLAUDE_PLUGIN_ROOT}`); the orchestrator sends ONLY the filled-in
|
|
33
|
+
template below.
|
|
34
|
+
|
|
35
|
+
## File protocol
|
|
36
|
+
|
|
37
|
+
- Output file: `reports/<TOPIC>/<YOUR-FOCUS>.md` where `<YOUR-FOCUS>` is the
|
|
38
|
+
underscore-separated aspect name (e.g. `clinical_landscape.md`).
|
|
39
|
+
- The write tool auto-creates parent directories - never use bash mkdir.
|
|
40
|
+
- The file must be self-contained: a reader should understand the findings,
|
|
41
|
+
the tools/queries used, and the sources cited without any other context.
|
|
42
|
+
- File structure: title, one-paragraph scope summary, findings with in-text
|
|
43
|
+
citations, tool/query log (which biomcp tools + key argument values), and a
|
|
44
|
+
full bibliography.
|
|
45
|
+
|
|
46
|
+
## Worker rules
|
|
47
|
+
|
|
48
|
+
1. Stay focused: execute only the assigned aspect; do NOT delegate to other
|
|
49
|
+
subagents (no re-delegation), and do not expand scope.
|
|
50
|
+
2. Tool selection: query biomcp tools per `references/tool-selection.md`;
|
|
51
|
+
filter at the source (specific terms, `limit`, `sections`) - never retrieve
|
|
52
|
+
broadly and filter locally.
|
|
53
|
+
3. Sequential MCP calls only - never issue concurrent biomcp calls. No manual
|
|
54
|
+
sleep timers are needed between calls (server-side limiters pace each
|
|
55
|
+
source); the only exceptions are HPA `protein_atlas`/`expression` sections
|
|
56
|
+
and GEO supplementary downloads, which are unthrottled - space those out.
|
|
57
|
+
4. No internal knowledge: use only biomcp tool results or official sources.
|
|
58
|
+
If evidence is missing after retries, say so explicitly in the report.
|
|
59
|
+
5. Citations: every claim gets [N] references; keep a numbered bibliography in
|
|
60
|
+
`references/citations.md` format. Capture identifiers as you go: PMIDs,
|
|
61
|
+
PMCIDs, DOIs, NCT IDs, patent IDs, GEO/SRA accessions, database IDs.
|
|
62
|
+
6. Retry logic: if a query fails, wait a few seconds, retry with a simpler
|
|
63
|
+
query; at most 3 attempts per query before recording the gap and moving on.
|
|
64
|
+
7. Writing: succinct, accurate, professional - academic standard.
|
|
65
|
+
|
|
66
|
+
## Retry ladder (per query)
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
attempt 1: original query
|
|
70
|
+
fail -> wait a few seconds
|
|
71
|
+
attempt 2: simplified query (fewer terms, broader limit)
|
|
72
|
+
fail -> wait a few seconds
|
|
73
|
+
attempt 3: alternate tool/source (see references/tool-selection.md routing)
|
|
74
|
+
fail -> record "evidence gap" in the aspect file with the failed query; continue
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Parallel execution (orchestrator with subagent/Task tool)
|
|
78
|
+
|
|
79
|
+
- Pick the tier by capability: dedicated `bioresearcher-dr-worker` subagent
|
|
80
|
+
(Tier A) when the harness offers it; otherwise generic subagents with the
|
|
81
|
+
inlined cheatsheet (Tier B). Do not mix tiers within one topic.
|
|
82
|
+
- Launch workers in parallel in batches of up to 5.
|
|
83
|
+
- Track each aspect in the todo list; mark complete when its output file
|
|
84
|
+
exists and ends with a bibliography.
|
|
85
|
+
- If a worker fails or stalls, restart it (same prompt), max 3 restarts.
|
|
86
|
+
- Tell the user up front: "If subagents are stuck without progress for too
|
|
87
|
+
long, interrupt and ask me to resume work."
|
|
88
|
+
|
|
89
|
+
## Sequential degradation (no subagent tool)
|
|
90
|
+
|
|
91
|
+
If the harness has no subagent/Task tool, the SAME protocol runs inline in the
|
|
92
|
+
main conversation, one aspect at a time:
|
|
93
|
+
|
|
94
|
+
1. Announce the aspect being worked on.
|
|
95
|
+
2. Apply Worker rules 2-7 exactly (same tool selection, retries, citation
|
|
96
|
+
discipline, file protocol).
|
|
97
|
+
3. Write `reports/<TOPIC>/<ASPECT>.md` before moving to the next aspect.
|
|
98
|
+
4. After the last aspect, proceed to synthesis (SKILL.md Step 5).
|
|
99
|
+
|
|
100
|
+
Sequential mode trades latency for context - keep per-aspect tool calls lean
|
|
101
|
+
(strict `limit`, narrow `sections`) so the accumulated context stays usable.
|
|
102
|
+
|
|
103
|
+
## Aspect completion checklist
|
|
104
|
+
|
|
105
|
+
- [ ] Output file exists at `reports/<TOPIC>/<ASPECT>.md`
|
|
106
|
+
- [ ] Every claim has a citation, source note, or method note
|
|
107
|
+
- [ ] Bibliography present, numbered by order of appearance
|
|
108
|
+
- [ ] Identifiers included (PMIDs / DOIs / NCT IDs / patent IDs / accessions)
|
|
109
|
+
- [ ] Tool/query log included
|
|
110
|
+
- [ ] Evidence gaps (if any) explicitly listed
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Convert a markdown research report to a standalone HTML file.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
uv run --with markdown python scripts/markdown-to-html.py report.md -o report.html
|
|
6
|
+
|
|
7
|
+
Dependencies:
|
|
8
|
+
- markdown (python-markdown), provided by `uv run --with markdown`
|
|
9
|
+
|
|
10
|
+
Wraps the rendered markdown in a minimal GitHub-like inline-CSS page so the
|
|
11
|
+
output is a single self-contained file with no external assets.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import sys
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
import markdown as md_lib
|
|
20
|
+
except ImportError:
|
|
21
|
+
sys.stderr.write(
|
|
22
|
+
"error: the 'markdown' package is required. Run via:\n"
|
|
23
|
+
" uv run --with markdown python scripts/markdown-to-html.py IN.md -o OUT.html\n"
|
|
24
|
+
)
|
|
25
|
+
sys.exit(2)
|
|
26
|
+
|
|
27
|
+
CSS = """
|
|
28
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
29
|
+
font-size: 16px; line-height: 1.6; color: #1f2328; background: #ffffff;
|
|
30
|
+
max-width: 980px; margin: 0 auto; padding: 32px 44px; }
|
|
31
|
+
h1, h2, h3, h4, h5, h6 { font-weight: 600; line-height: 1.25; margin-top: 24px;
|
|
32
|
+
margin-bottom: 16px; }
|
|
33
|
+
h1 { font-size: 2em; border-bottom: 1px solid #d1d9e0; padding-bottom: .3em; }
|
|
34
|
+
h2 { font-size: 1.5em; border-bottom: 1px solid #d1d9e0; padding-bottom: .3em; }
|
|
35
|
+
h3 { font-size: 1.25em; }
|
|
36
|
+
p { margin-top: 0; margin-bottom: 16px; }
|
|
37
|
+
a { color: #0969da; text-decoration: none; }
|
|
38
|
+
a:hover { text-decoration: underline; }
|
|
39
|
+
code { font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
|
|
40
|
+
font-size: 85%; padding: .2em .4em; background: #f0f2f5; border-radius: 6px; }
|
|
41
|
+
pre { background: #f6f8fa; border-radius: 6px; padding: 16px; overflow: auto; }
|
|
42
|
+
pre code { background: transparent; padding: 0; font-size: 85%; }
|
|
43
|
+
blockquote { border-left: .25em solid #d1d9e0; color: #59636e; padding: 0 1em;
|
|
44
|
+
margin: 0 0 16px 0; }
|
|
45
|
+
table { border-collapse: collapse; margin-bottom: 16px; display: block;
|
|
46
|
+
overflow: auto; max-width: 100%; }
|
|
47
|
+
table th, table td { border: 1px solid #d1d9e0; padding: 6px 13px; }
|
|
48
|
+
table tr:nth-child(2n) { background: #f6f8fa; }
|
|
49
|
+
ul, ol { margin-bottom: 16px; padding-left: 2em; }
|
|
50
|
+
hr { height: .25em; background: #d1d9e0; border: 0; margin: 24px 0; }
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def convert(markdown_path: Path, title: str) -> str:
|
|
55
|
+
text = markdown_path.read_text(encoding="utf-8")
|
|
56
|
+
body = md_lib.markdown(text, extensions=["tables", "fenced_code", "sane_lists"])
|
|
57
|
+
return (
|
|
58
|
+
"<!DOCTYPE html>\n"
|
|
59
|
+
'<html lang="en">\n<head>\n<meta charset="utf-8">\n'
|
|
60
|
+
f"<title>{title}</title>\n"
|
|
61
|
+
f"<style>{CSS}</style>\n</head>\n<body>\n{body}\n</body>\n</html>\n"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def main() -> None:
|
|
66
|
+
parser = argparse.ArgumentParser(
|
|
67
|
+
description="Convert a markdown file to standalone GitHub-like HTML."
|
|
68
|
+
)
|
|
69
|
+
parser.add_argument("input", help="input markdown file")
|
|
70
|
+
parser.add_argument("-o", "--output", help="output HTML file (default: input with .html)")
|
|
71
|
+
parser.add_argument("--title", help="HTML <title> (default: input filename stem)")
|
|
72
|
+
args = parser.parse_args()
|
|
73
|
+
|
|
74
|
+
src = Path(args.input)
|
|
75
|
+
if not src.is_file():
|
|
76
|
+
sys.stderr.write(f"error: no such file: {src}\n")
|
|
77
|
+
sys.exit(1)
|
|
78
|
+
|
|
79
|
+
out = Path(args.output) if args.output else src.with_suffix(".html")
|
|
80
|
+
title = args.title or src.stem.replace("_", " ").replace("-", " ").title()
|
|
81
|
+
out.write_text(convert(src, title), encoding="utf-8")
|
|
82
|
+
print(f"wrote {out}")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
if __name__ == "__main__":
|
|
86
|
+
main()
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bioresearcher-plot-making
|
|
3
|
+
description: "Biomedical visualization router and plotting engine: classifies research data and produces publication-ready scientific figures (structural protein-binder complexes, conformational dynamics, literature method summaries, developmental case registers, and evidence tables). Use when asked to plot, visualize, graph, or chart biomedical data, PDB complexes, binding modes, literature searches, or translational safety cases."
|
|
4
|
+
license: Apache-2.0
|
|
5
|
+
compatibility: "Any Agent Skills harness with Python 3.10+ and uv; matplotlib, pymupdf, numpy, pillow, pymol (optional for 3D)"
|
|
6
|
+
metadata:
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
source: "bioresearcher-skills"
|
|
9
|
+
allowed-tools: Bash Read Write Edit Glob Grep
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Bioresearcher Plot-Making: Visual Dispatcher & Production Engine
|
|
13
|
+
|
|
14
|
+
This skill serves as the central router and quality assurance engine for
|
|
15
|
+
producing publication-grade scientific figures. It directs requests to
|
|
16
|
+
specialized domain plotting specifications, enforces declarative data
|
|
17
|
+
contracts, and verifies outputs against deterministic geometric QA gates.
|
|
18
|
+
|
|
19
|
+
## 1. Decision Matrix & Routing Table
|
|
20
|
+
|
|
21
|
+
Inspect the research request and input data to select the corresponding plot
|
|
22
|
+
type. Immediately load the detailed specification document using `Read`:
|
|
23
|
+
|
|
24
|
+
| Generalized Plot Type | Input Data & Research Context | Reference Specification |
|
|
25
|
+
| :--- | :--- | :--- |
|
|
26
|
+
| **`structural-biology_binder-visualization`** | PDB/mmCIF coordinates, structural conformer comparisons, RMSF trajectories, multi-ligand binding modes, residue contact matrices (BSA, H-bonds, salt bridges). | [Structural Biology Guide](references/structural-biology-binder-visualization.md) |
|
|
27
|
+
| **`literature-search_method-summary`** | Biomedical literature syntheses, translational risk pathways, developmental drug case registers (preclinical $\to$ approved), preclinical assay detection cascades, structured evidence tables. | [Literature Summary Guide](references/literature-search-method-summary.md) |
|
|
28
|
+
| **`qa-gates-and-gotchas`** | Multi-panel alignment troubleshooting, vector collision audit failures, minimum glyph size compliance, hard-earned gotchas. | [QA Gates and Gotchas Guide](references/qa-gates-and-gotchas.md) |
|
|
29
|
+
|
|
30
|
+
Do not generate plotting code without loading the corresponding reference guide.
|
|
31
|
+
|
|
32
|
+
## 2. Production Workflow
|
|
33
|
+
|
|
34
|
+
Follow this five-step workflow for all visualization requests:
|
|
35
|
+
|
|
36
|
+
### Step 1: Classify and Load Domain Specification
|
|
37
|
+
|
|
38
|
+
Identify the appropriate archetype from the Decision Matrix above. Load the
|
|
39
|
+
corresponding specification via `Read` (e.g. `Read references/structural-biology-binder-visualization.md`).
|
|
40
|
+
|
|
41
|
+
### Step 2: Ingest and Validate Declarative Data Contracts
|
|
42
|
+
|
|
43
|
+
Ensure input data conforms to the required schema before writing plotting code:
|
|
44
|
+
- **Structural Dynamics**: `conformer_rmsf.tsv` (`resnum`, `chain_role`, `domain`, `displacement_A`).
|
|
45
|
+
- **Interaction Matrix**: `binder_hotspot_matrix.tsv` (composite `<site>:<residue>` headers, triple-encoded cells `BSA_A2|HBOND|SALTBRIDGE`).
|
|
46
|
+
- **Case Register**: `literature_cases.tsv` (`entity_name`, `hazard_description`, `development_stage`, `status`, `pmids`).
|
|
47
|
+
- **Detection Cascade**: `assay_cascade.tsv` (`assay_name`, `readout`, `method_family`, `screening_stage`, `pmids`).
|
|
48
|
+
- **Evidence Matrix**: `evidence_table.tsv` (`citation`, `test_system`, `sample_matrix`, `analytical_method`, `readout`).
|
|
49
|
+
|
|
50
|
+
### Step 3: Verify uv Python Environment & Dependencies
|
|
51
|
+
|
|
52
|
+
Never rely on globally installed host packages. Ensure the project-local uv
|
|
53
|
+
environment is configured (via `bioresearcher-python-setup-uv`) with all
|
|
54
|
+
required visualization libraries:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
./uv venv .venv
|
|
58
|
+
VIRTUAL_ENV="$(pwd)/.venv" ./uv pip install pymol-open-source matplotlib pymupdf numpy pillow biopython pandas
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
If `bioresearcher-python-setup-uv` already raced and exported `UV_INDEX_URL`, keep it exported — these installs inherit it automatically.
|
|
62
|
+
|
|
63
|
+
The `VIRTUAL_ENV` pin is mandatory: on hosts with an active conda/mamba environment (`CONDA_PREFIX`), bare `./uv pip install` silently targets the HOST environment instead of `./.venv`.
|
|
64
|
+
|
|
65
|
+
Never execute plotting scripts that write outputs to the workspace root:
|
|
66
|
+
- Create a dedicated target directory: `figures/<TARGET>/`.
|
|
67
|
+
- Place or generate data files directly inside `figures/<TARGET>/`.
|
|
68
|
+
- Ensure all Python scripts resolve relative paths via `Path(__file__).resolve().parent`.
|
|
69
|
+
|
|
70
|
+
### Step 4: Execute Deterministic Plotting Script
|
|
71
|
+
|
|
72
|
+
Run the figure generation script using the project-local interpreter:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
./.venv/bin/python fig1.py
|
|
76
|
+
# Or for standalone PyMOL scripts:
|
|
77
|
+
# ./.venv/bin/pymol -cq render_script.py
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Step 5: Enforce Three-Layer Quality Assurance (QA)
|
|
81
|
+
|
|
82
|
+
Certify figures before delivery:
|
|
83
|
+
1. **Layer 1 (Static Source Preflight)**: Enforce standard typography (`font.family='sans-serif'`, base size 7 pt) and vector formats (`pdf.fonttype=42`, `svg.fonttype='none'`).
|
|
84
|
+
2. **Layer 2 (Deterministic Geometry Gates)**:
|
|
85
|
+
- Run panel alignment gate (`audit_panel_alignment.py`): max deviation $\le 1.5\text{ pt}$.
|
|
86
|
+
- Run vector collision audit (`audit_figure_collisions.py`): 0 FAIL.
|
|
87
|
+
- Run font floor audit (`audit_pdf_text.py`): minimum glyph size $\ge 5.0\text{ pt}$.
|
|
88
|
+
3. **Layer 3 (Vision Model Semantic Review)**: Ask focused, single-question queries to verify biological topology and icon orientation.
|
|
89
|
+
|
|
90
|
+
## 3. Core Gotchas Summary
|
|
91
|
+
|
|
92
|
+
- **CWD Drift**: Relative save paths silently write to the process cwd; always verify outputs exist in the target directory with fresh timestamps.
|
|
93
|
+
- **Probe Render Trick**: Never render 3D text labels in PyMOL; extract 2D projection coordinates via a probe pass (`render_anchors.json`) and draw native vector text in Matplotlib.
|
|
94
|
+
- **Contact-Fragment Pruning**: Superimposing full macromolecules buries the receptor; prune ligands to residues within 8 Å plus 3-residue extension.
|
|
95
|
+
- **Dynamic Text Advance**: Use `right_edge()` taking `max(ink_bbox, advance_width)` to space inline text; character-count heuristics fail on proportional fonts.
|
|
96
|
+
- **Baseline Staggering**: Alternate column header baselines ($y=9.50$ vs $8.98$) to prevent PDF parsers from merging adjacent text runs.
|
|
97
|
+
- **Aspect Ratio Desync**: Panels sharing a row with `aspect='equal'` will letterbox and drift vertically unless physical aspect ratios match.
|