TREM2 agonism vs antagonism in DAM microglia¶
Notebook ID: nb-SDA-2026-04-02-gap-001 · Analysis: SDA-2026-04-02-gap-001 · Generated: 2026-04-10
Research question¶
The disease-associated microglia (DAM) phenotype involves TREM2 upregulation, but whether therapeutic agonism or antagonism of TREM2 is beneficial remains contested across disease stages.
Approach¶
This notebook is generated programmatically from real Forge tool calls and SciDEX debate data. Code cells load cached evidence bundles from data/forge_cache/seaad/*.json and query live data from scidex.db. Re-run python3 scripts/regenerate_notebooks.py --analysis SDA-2026-04-02-gap-001 --force to refresh.
7 hypotheses were generated and debated. The knowledge graph has 0 edges.
Debate Summary¶
Quality score: 0.552 · Rounds: 4 · Personas: Theorist, Skeptic, Domain_Expert, Synthesizer
1. Forge tool provenance¶
import json, sys, sqlite3
from pathlib import Path
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
matplotlib.rcParams['figure.dpi'] = 110
matplotlib.rcParams['figure.facecolor'] = 'white'
REPO = Path('.').resolve()
sys.path.insert(0, str(REPO))
CACHE_SUB = 'seaad'
CACHE = REPO / 'data' / 'forge_cache' / CACHE_SUB
def load(name):
p = CACHE / f'{name}.json'
if p.exists():
return json.loads(p.read_text())
return {}
db_path = Path('/home/ubuntu/scidex/scidex.db')
try:
db = sqlite3.connect(str(db_path))
prov = pd.read_sql_query('''
SELECT skill_id, status, COUNT(*) AS n_calls,
ROUND(AVG(duration_ms),0) AS mean_ms
FROM tool_calls
WHERE created_at >= date('now','-30 days')
GROUP BY skill_id, status
ORDER BY n_calls DESC
''', db)
db.close()
prov['tool'] = prov['skill_id'].str.replace('tool_', '', regex=False)
print(f'{len(prov)} tool-call aggregates (last 30 days):')
prov[['tool','status','n_calls','mean_ms']].head(20)
except Exception as e:
print(f'Provenance unavailable: {e}')
Provenance unavailable: Execution failed on sql '
SELECT skill_id, status, COUNT(*) AS n_calls,
ROUND(AVG(duration_ms),0) AS mean_ms
FROM tool_calls
WHERE created_at >= date('now','-30 days')
GROUP BY skill_id, status
ORDER BY n_calls DESC
': database disk image is malformed
2. Target gene annotations¶
ann_rows = []
for g in ['APOE', 'MAPT', 'SYK', 'TYROBP']:
mg = load(f'mygene_{g}')
hpa = load(f'hpa_{g}')
if not mg and not hpa:
ann_rows.append({'gene': g, 'name': '—', 'protein_class': '—',
'disease_involvement': '—'})
continue
ann_rows.append({
'gene': g,
'name': (mg.get('name') or '')[:55],
'protein_class': ', '.join((hpa.get('protein_class') or [])[:2])[:55]
if isinstance(hpa.get('protein_class'), list)
else str(hpa.get('protein_class') or '—')[:55],
'disease_involvement': ', '.join((hpa.get('disease_involvement') or [])[:2])[:55]
if isinstance(hpa.get('disease_involvement'), list)
else str(hpa.get('disease_involvement') or '')[:55],
})
pd.DataFrame(ann_rows)
| gene | name | protein_class | disease_involvement | |
|---|---|---|---|---|
| 0 | APOE | apolipoprotein E | Cancer-related genes, Candidate cardiovascular... | Alzheimer disease, Amyloidosis |
| 1 | MAPT | microtubule associated protein tau | — | |
| 2 | SYK | — | — | — |
| 3 | TYROBP | transmembrane immune signaling adaptor TYROBP | Disease related genes, Human disease related g... |
3. GO Biological Process enrichment (Enrichr)¶
go_bp = load('enrichr_GO_Biological_Process')
if isinstance(go_bp, list) and go_bp:
go_df = pd.DataFrame(go_bp[:10])[['term','p_value','odds_ratio','genes']]
go_df['p_value'] = go_df['p_value'].apply(lambda p: f'{p:.2e}')
go_df['odds_ratio'] = go_df['odds_ratio'].round(1)
go_df['term'] = go_df['term'].str[:60]
go_df['n_hits'] = go_df['genes'].apply(len)
go_df['genes'] = go_df['genes'].apply(lambda g: ', '.join(g))
go_df[['term','n_hits','p_value','odds_ratio','genes']]
else:
print('No GO:BP enrichment data')
# Visualize top GO BP enrichment
go_bp = load('enrichr_GO_Biological_Process')
if isinstance(go_bp, list) and go_bp:
top = go_bp[:8]
terms = [t['term'][:45] for t in top][::-1]
neglogp = [-np.log10(max(t['p_value'], 1e-300)) for t in top][::-1]
fig, ax = plt.subplots(figsize=(9, 4.5))
ax.barh(terms, neglogp, color='#4fc3f7')
ax.set_xlabel('-log10(p-value)')
ax.set_title('Top GO:BP enrichment (Enrichr)')
ax.grid(axis='x', alpha=0.3)
plt.tight_layout(); plt.show()
else:
print('No GO:BP data to plot')
4. KEGG pathway enrichment¶
kegg = load('enrichr_KEGG_Pathways')
if isinstance(kegg, list) and kegg:
kegg_df = pd.DataFrame(kegg[:10])[['term','p_value','odds_ratio','genes']]
kegg_df['genes'] = kegg_df['genes'].apply(lambda g: ', '.join(g))
kegg_df['p_value'] = kegg_df['p_value'].apply(lambda p: f'{p:.2e}')
kegg_df['odds_ratio'] = kegg_df['odds_ratio'].round(1)
kegg_df
else:
print('No KEGG enrichment data')
No KEGG enrichment data
5. STRING protein interaction network¶
ppi = load('string_network')
if isinstance(ppi, list) and ppi:
ppi_df = pd.DataFrame(ppi).sort_values('score', ascending=False)
display_cols = [c for c in ['protein1','protein2','score','escore','tscore'] if c in ppi_df.columns]
print(f'{len(ppi_df)} STRING edges')
ppi_df[display_cols].head(20)
else:
print('No STRING edges returned')
11 STRING edges
# Network figure
ppi = load('string_network')
if isinstance(ppi, list) and ppi:
import math
nodes = sorted({p for e in ppi for p in (e['protein1'], e['protein2'])})
n = len(nodes)
pos = {n_: (math.cos(2*math.pi*i/n), math.sin(2*math.pi*i/n)) for i, n_ in enumerate(nodes)}
fig, ax = plt.subplots(figsize=(7, 7))
for e in ppi:
x1,y1 = pos[e['protein1']]; x2,y2 = pos[e['protein2']]
ax.plot([x1,x2],[y1,y2], color='#888', alpha=0.3+0.5*e['score'],
linewidth=0.5+2*e['score'])
for name,(x,y) in pos.items():
ax.scatter([x],[y], s=450, color='#ffd54f', edgecolors='#333', zorder=3)
ax.annotate(name, (x,y), ha='center', va='center', fontsize=8, fontweight='bold', zorder=4)
ax.set_aspect('equal'); ax.axis('off')
ax.set_title(f'STRING PPI network ({len(ppi)} edges)')
plt.tight_layout(); plt.show()
else:
print('No STRING data to visualize')
6. Reactome pathway footprint¶
pw_rows = []
for g in ['APOE', 'MAPT', 'SYK', 'TYROBP']:
pws = load(f'reactome_{g}')
if isinstance(pws, list):
pw_rows.append({'gene': g, 'n_pathways': len(pws),
'top_pathway': (pws[0]['name'] if pws else '—')[:70]})
else:
pw_rows.append({'gene': g, 'n_pathways': 0, 'top_pathway': '—'})
pd.DataFrame(pw_rows).sort_values('n_pathways', ascending=False)
| gene | n_pathways | top_pathway | |
|---|---|---|---|
| 0 | APOE | 8 | Nuclear signaling by ERBB4 |
| 3 | TYROBP | 6 | Immunoregulatory interactions between a Lympho... |
| 1 | MAPT | 3 | Caspase-mediated cleavage of cytoskeletal prot... |
| 2 | SYK | 0 | — |
7. Allen Brain Atlas ISH regional expression¶
ish_rows = []
for g in ['APOE', 'MAPT', 'SYK', 'TYROBP']:
ish = load(f'allen_ish_{g}')
regions = ish.get('regions') or [] if isinstance(ish, dict) else []
ish_rows.append({
'gene': g,
'n_ish_regions': len(regions),
'top_region': (regions[0].get('structure','') if regions else '—')[:45],
'top_energy': round(regions[0].get('expression_energy',0), 2) if regions else None,
})
pd.DataFrame(ish_rows)
| gene | n_ish_regions | top_region | top_energy | |
|---|---|---|---|---|
| 0 | APOE | 0 | — | — |
| 1 | MAPT | 0 | — | — |
| 2 | SYK | 0 | — | — |
| 3 | TYROBP | 0 | — | — |
8. Hypothesis ranking (7 hypotheses)¶
hyp_data = [('TREM2-APOE4 Co-targeting — Simultaneous Correction of L', 0.559), ('Stage-Selective TREM2 Agonism — Boosting DAM Phagocytos', 0.526), ('Stage-Specific TREM2 Biomarker-Guided Switching — Agoni', 0.523), ('TREM2 Antagonism in Late-Stage Tauopathy — Reducing Neu', 0.52), ('TREM2 R47H Variant Correction — AAV-Mediated Rescue of ', 0.512), ('Soluble TREM2 (sTREM2) as Therapeutic Mimic — Decouplin', 0.494), ('TREM2-DAP12 Signalosome Enhancement — Boosting PI3K-AKT', 0.493)]
titles = [h[0] for h in hyp_data][::-1]
scores = [h[1] for h in hyp_data][::-1]
fig, ax = plt.subplots(figsize=(10, max(8, len(titles)*0.4)))
colors = ['#ef5350' if s >= 0.6 else '#ffa726' if s >= 0.5 else '#66bb6a' for s in scores]
ax.barh(range(len(titles)), scores, color=colors)
ax.set_yticks(range(len(titles))); ax.set_yticklabels(titles, fontsize=7)
ax.set_xlabel('Composite Score'); ax.set_title('TREM2 agonism vs antagonism in DAM microglia')
ax.grid(axis='x', alpha=0.3)
plt.tight_layout(); plt.show()
9. Score dimension heatmap (top 10)¶
labels = ['TREM2-APOE4 Co-targeting — Simultaneous ', 'Stage-Selective TREM2 Agonism — Boosting', 'Stage-Specific TREM2 Biomarker-Guided Sw', 'TREM2 Antagonism in Late-Stage Tauopathy', 'TREM2 R47H Variant Correction — AAV-Medi', 'Soluble TREM2 (sTREM2) as Therapeutic Mi', 'TREM2-DAP12 Signalosome Enhancement — Bo']
matrix = np.array([[0.76, 0.6, 0.88, 0.65, 0, 0.65, 0.6, 0.6, 0.58], [0.65, 0.68, 0.82, 0.65, 0, 0.65, 0.6, 0.6, 0.58], [0.85, 0.48, 0.78, 0.65, 0, 0.65, 0.6, 0.6, 0.58], [0.72, 0.55, 0.7, 0.65, 0, 0.65, 0.6, 0.6, 0.58], [0.68, 0.58, 0.85, 0.65, 0, 0.65, 0.6, 0.6, 0.58], [0.78, 0.62, 0.75, 0.65, 0, 0.65, 0.6, 0.6, 0.58], [0.8, 0.55, 0.73, 0.65, 0, 0.65, 0.6, 0.6, 0.58]])
dims = ['novelty_score', 'feasibility_score', 'impact_score', 'mechanistic_plausibility_score', 'clinical_relevance_score', 'data_availability_score', 'reproducibility_score', 'druggability_score', 'safety_profile_score']
if matrix.size:
fig, ax = plt.subplots(figsize=(10, 5))
im = ax.imshow(matrix, cmap='RdYlGn', aspect='auto', vmin=0, vmax=1)
ax.set_xticks(range(len(dims)))
ax.set_xticklabels([d.replace('_score','').replace('_',' ').title() for d in dims],
rotation=45, ha='right', fontsize=8)
ax.set_yticks(range(len(labels))); ax.set_yticklabels(labels, fontsize=7)
ax.set_title('Score dimensions — top hypotheses')
plt.colorbar(im, ax=ax, shrink=0.8)
plt.tight_layout(); plt.show()
else:
print('No score data available')
10. PubMed evidence per hypothesis¶
Hypothesis 1: TREM2-APOE4 Co-targeting — Simultaneous Correction of Lipid Sensing an¶
Target genes: TREM2, APOE · Composite score: 0.559
Core Hypothesis and Rationale¶
The central hypothesis posits that the therapeutic failure of single-target TREM2 interventions in Alzheimer's disease (AD) may be mechanistically explained by the epistatic relationship between TREM2 signaling and APOE4-mediated lipid dyshomeostasis in disease-associated microglia (DAM). Specifically, we hypothesize that APOE4 expression creates a cell-intrinsic lipid trafficking defect that renders DAM functionally refractory to TREM2 agonism, and that simulta
hid = 'h-trem2-f48baa0c'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 2: Stage-Selective TREM2 Agonism — Boosting DAM Phagocytosis in Early Amy¶
Target genes: TREM2 · Composite score: 0.526
Stage-Selective TREM2 Agonism — Boosting DAM Phagocytosis in Early Amyloid Phase¶
Background and Biological Rationale¶
TREM2 (Triggering Receptor Expressed on Myeloid Cells 2) is a surface receptor expressed predominantly on microglia and macrophages throughout the central nervous system. It belongs to the immunoglobulin superfamily and signals through the adaptor protein DAP12 (DNAX Activation Protein of 12 kDa), which contains an immunoreceptor tyrosine-based activation motif (ITAM). Up
hid = 'h-trem2-3374766c'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 3: Stage-Specific TREM2 Biomarker-Guided Switching — Agonist in Amyloid P¶
Target genes: TREM2, APOE, MAPT · Composite score: 0.523
Core Hypothesis and Rationale¶
This hypothesis proposes that the therapeutic polarity of TREM2 modulation in Alzheimer's disease must be dynamically inverted according to the dominant pathological phase: TREM2 agonism is beneficial during the amyloid-dominant early phase (Braak NFT stages I–II, amyloid PET-positive/tau PET-negative or low), whereas TREM2 antagonism becomes preferable during the tau-dominant late phase (Braak stages IV–VI, high tau PET burden with established neurodegeneration
hid = 'h-trem2-6a46fa2c'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 4: TREM2 Antagonism in Late-Stage Tauopathy — Reducing Neuroinflammatory¶
Target genes: TREM2 · Composite score: 0.52
TREM2 Antagonism in Late-Stage Tauopathy — Reducing Neuroinflammatory Amplification¶
Background: The Dual Role of TREM2 Across Disease Stages¶
The hypothesis that TREM2 antagonism could be therapeutically beneficial in late-stage tauopathy represents a paradigm-shifting reframe of TREM2 as a context-dependent, stage-specific target rather than a uniformly beneficial immune modulator. This reframing emerges from a sophisticated understanding of microglial biology that has evolved substanti
hid = 'h-trem2-883b6abd'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 5: TREM2 R47H Variant Correction — AAV-Mediated Rescue of Common Risk All¶
Target genes: TREM2 · Composite score: 0.512
TREM2 R47H Variant Correction — AAV-Mediated Rescue of Common Risk Allele¶
TREM2 R47H as the Preeminent AD Risk Variant¶
The R47H variant of TREM2 (rs75932628) represents one of the strongest known genetic risk factors for Alzheimer's disease, with an odds ratio of approximately 2.5-3.0 for heterozygous carriers — comparable to the risk conferred by the APOE ε4 allele, though with a different mechanistic basis and pattern of risk modification. This variant was originally identified throug
hid = 'h-trem2-8df94363'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 6: Soluble TREM2 (sTREM2) as Therapeutic Mimic — Decoupling Phagocytosis¶
Target genes: TREM2, ADAM10, ADAM17 · Composite score: 0.494
Soluble TREM2 (sTREM2) as Therapeutic Mimic — Decoupling Phagocytosis from Inflammation¶
The Central Paradox of TREM2 Biology¶
TREM2 signaling presents a fundamental therapeutic paradox: the receptor's beneficial phagocytic functions and its potentially harmful inflammatory amplification effects are mediated through the same DAP12-ITAM-SYK signaling axis. Classical receptor pharmacology suggests that a single downstream cascade cannot easily be selectively activated to produce one set of
hid = 'h-trem2-fe8c644a'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 7: TREM2-DAP12 Signalosome Enhancement — Boosting PI3K-AKT-mTOR Axis for¶
Target genes: TREM2, TYROBP, SYK, PI3K · Composite score: 0.493
Core Hypothesis and Rationale¶
The central hypothesis posits that selective enhancement of the TREM2-DAP12 signalosome—specifically by augmenting downstream PI3K-AKT-mTOR axis signaling—will restore and sustain the metabolic fitness required for disease-associated microglia (DAM) to execute their neuroprotective amyloid surveillance functions during the early-to-mid stages of Alzheimer's disease pathology. This hypothesis explicitly sides with the agonist camp of the TREM2 debate, but with a
hid = 'h-trem2-f3effd21'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
11. Knowledge graph edges (0 total)¶
edge_data = []
if edge_data:
pd.DataFrame(edge_data).head(25)
else:
print('No KG edge data available')
No KG edge data available
12. Caveats¶
This notebook uses real Forge tool calls cached from live APIs, but:
- Enrichment is against curated gene-set libraries, not genome-wide screens
- STRING/Reactome/HPA/MyGene reflect curated knowledge
- PubMed literature is search-relevance ranked, not systematic review
The cached evidence bundle is the minimum viable real-data analysis for this topic.