Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: build validate audit eval site graph track synthesize recap-dry clockbench fair repos check help
.PHONY: build validate audit eval site graph track synthesize recap-dry clockbench fair repos hub check help

help:
@echo "longevity-loop — an AI-native compounding loop for aging science"
Expand All @@ -10,7 +10,8 @@ help:
@echo " make clockbench Cross-clock disagreement benchmark (measures gaps-analysis G1)"
@echo " make fair Score open aging datasets for FAIR/reproducibility → docs/FAIR.md (G2)"
@echo " make repos Per-repo KG + agentic-tooling generation recipes → docs/REPOS.md (hub)"
@echo " make check validate + audit + eval + clockbench + fair + repos + build drift-gate (CI finish line)"
@echo " make hub Validate the JIT deep artifacts under hub/ (add --refresh for staleness)"
@echo " make check validate + audit + eval + clockbench + fair + repos + hub + build drift-gate (CI finish line)"

build:
python3 scripts/build.py
Expand Down Expand Up @@ -59,13 +60,20 @@ fair:
repos:
python3 scripts/repos.py

# Finish line: data well-formed, still an AI-native loop, executions honestly eval'd
# (no fake ✅), the clock-disagreement + FAIR + repo-recipe artifacts self-verify, and docs match.
# Validate the hub's JIT deep artifacts (hub/<repo>/: KG + skill + SHA-stamped manifest).
# `make hub` = offline integrity gate; `python3 scripts/hub_gen.py --refresh` = network staleness.
hub:
python3 scripts/hub_gen.py --check

# Finish line: data well-formed, still an AI-native loop, executions honestly eval'd (no fake ✅),
# the clock-disagreement + FAIR + repo-recipe + hub artifacts self-verify, and docs match.
check: validate audit eval
python3 scripts/clockbench.py --selftest
python3 scripts/fair.py --selftest
python3 scripts/fair.py --gate
python3 scripts/fair.py --check
python3 scripts/repos.py --selftest
python3 scripts/repos.py --check
python3 scripts/hub_gen.py --selftest
python3 scripts/hub_gen.py --check
python3 scripts/build.py --check
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ Sequenced bridge: convert the computational finding + your credential network (G

<h2 id="execution">✅ Roadmap Execution</h2>

**12/23 done (52%).** Each execution is a checkbox with a before→after eval; a box only ticks with a real result (`done` requires a non-pending before AND after — no evidence ⇒ not done, gated in CI).
**13/24 done (54%).** Each execution is a checkbox with a before→after eval; a box only ticks with a real result (`done` requires a non-pending before AND after — no evidence ⇒ not done, gated in CI).

- [x] **E1** (P1 · Foundation) — Stand up the AI-native loop (repo + self-audit + gated `make check`)
- [x] **E2** (P1 · Foundation) — Map the field into a verified knowledge base
Expand All @@ -182,6 +182,7 @@ Sequenced bridge: convert the computational finding + your credential network (G
- [x] **E21** (P1 · Foundation) — Problem map: top aging problems as a relationship graph + the one target + low-hanging fruit
- [x] **E22** (P1 · Foundation) — Publish the tracker.json data contract for the interactive portfolio instance (data-first slice)
- [x] **E23** (P1 · Foundation) — Hub architecture (knowledge·tooling·experts per cited repo) + the per-repo generation-recipe layer
- [x] **E24** (P1 · Foundation) — Hub Phase-2: JIT deep artifacts for one repo (pyaging) — knowledge graph + gated skill, SHA-stamped

### Eval reports — before → after

Expand Down Expand Up @@ -210,6 +211,7 @@ Sequenced bridge: convert the computational finding + your credential network (G
| ✅ E21 | a clear, visual answer to 'what are we shooting, and what's the quick win' | gaps ranked (gaps-analysis.md) but relationships + the single target + quick wins were implicit | docs/PROBLEMS.md — Mermaid relationship graph (G1 measurement = root bottleneck we target) + top-problems table + how/when/why + 3 low-hanging fruit with done-when; README pointer |
| ✅ E22 | a stable, derived JSON contract the agentic-portfolio instance can consume (no drift) | no machine-readable mission/progress feed for an external interactive surface | site/tracker.json — mission + 48% progress + 21 milestones + roadmap + low-hanging + frontier + 12 hubs + links, generated by build_site.py, deployed on Pages |
| ✅ E23 | a fresh, cheap, future-proof way to offer a KG + agentic tooling for each cited repo | cited repos listed in stack.yml but no KG/tooling per repo; no design for how to do it well | docs/HUB_ARCHITECTURE.md (index+JIT design; reuse graphify/understand/reverse; MCP; SHA-cached) + scripts/repos.py → docs/REPOS.md (22 repos, per-repo KG + reverse recipes), gated in make check |
| ✅ E24 | a real, grounded, provenance-stamped KG + skill generated from a cited repo, with a freshness gate | hub had the recipe layer only; no deep artifact proving the JIT layer works | hub/pyaging/ — knowledge-graph.json (20 nodes/edges) + compute-aging-clocks SKILL.md + manifest (SHA c2b3000e3c2c); scripts/hub_gen.py gates integrity (make check) + checks live staleness (FRESH); grounded in pyaging's real API |

---

Expand All @@ -232,7 +234,7 @@ Sequenced bridge: convert the computational finding + your credential network (G

<h2 id="hub">🧩 Knowledge · Tooling · Experts hub</h2>

This repo is a **hub**: for each cited repo it offers a knowledge graph (knowledge) + agentic tooling (skills/plugins/workflows), and links them to the experts who build them. Design (high-quality · fast · cheap · fresh · future-proof): **[docs/HUB_ARCHITECTURE.md](docs/HUB_ARCHITECTURE.md)** · per-repo generation recipes: **[docs/REPOS.md](docs/REPOS.md)**. Fresh index, just-in-time depth — deep artifacts are generated on demand and cached by commit SHA, never committed stale.
This repo is a **hub**: for each cited repo it offers a knowledge graph (knowledge) + agentic tooling (skills/plugins/workflows), and links them to the experts who build them. Design (high-quality · fast · cheap · fresh · future-proof): **[docs/HUB_ARCHITECTURE.md](docs/HUB_ARCHITECTURE.md)** · per-repo generation recipes: **[docs/REPOS.md](docs/REPOS.md)**. Fresh index, just-in-time depth — deep artifacts are generated on demand and cached by commit SHA, never committed stale. First deep exemplar (Phase 2): **[hub/pyaging](hub/pyaging)** — a grounded knowledge graph + a gated skill, SHA-stamped, with a live staleness check (`make hub` / `scripts/hub_gen.py --refresh`).

---

Expand Down
9 changes: 9 additions & 0 deletions data/executions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,12 @@
before: "cited repos listed in stack.yml but no KG/tooling per repo; no design for how to do it well"
after: "docs/HUB_ARCHITECTURE.md (index+JIT design; reuse graphify/understand/reverse; MCP; SHA-cached) + scripts/repos.py → docs/REPOS.md (22 repos, per-repo KG + reverse recipes), gated in make check"
proof: "docs/HUB_ARCHITECTURE.md · scripts/repos.py · docs/REPOS.md · make check"
- id: E24
phase: "P1 · Foundation"
item: "Hub Phase-2: JIT deep artifacts for one repo (pyaging) — knowledge graph + gated skill, SHA-stamped"
done: true
eval:
metric: "a real, grounded, provenance-stamped KG + skill generated from a cited repo, with a freshness gate"
before: "hub had the recipe layer only; no deep artifact proving the JIT layer works"
after: "hub/pyaging/ — knowledge-graph.json (20 nodes/edges) + compute-aging-clocks SKILL.md + manifest (SHA c2b3000e3c2c); scripts/hub_gen.py gates integrity (make check) + checks live staleness (FRESH); grounded in pyaging's real API"
proof: "hub/pyaging/* · scripts/hub_gen.py · docs/HUB_ARCHITECTURE.md"
56 changes: 56 additions & 0 deletions hub/pyaging/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
name: compute-aging-clocks
description: Compute a panel of biological-age (epigenetic) clocks from methylation/omics data with pyaging, then hand the panel to clockbench to quantify cross-clock disagreement. Trigger when you need biological-age estimates, a clock panel, or the disagreement signal for the Biomarkers-of-Aging / Turn-01 work.
source: rsinghlab/pyaging @ c2b3000e3c2c
license: BSD-3-Clause (pyaging)
generated_by: longevity-loop hub (scripts/hub_gen.py) — grounded in the pyaging repo + docs, not invented
---

# compute-aging-clocks (via pyaging)

Generated by the longevity-loop **hub** (docs/HUB_ARCHITECTURE.md) as the Phase-2 exemplar of
just-in-time deep tooling. Grounded in pyaging's real API at the pinned `source` SHA — regenerate
when that SHA changes (`scripts/hub_gen.py --refresh` flags staleness).

## When to use
You have methylation (or RNA-seq / ATAC / blood-chemistry) data and need biological-age estimates
from a **panel** of clocks — e.g. to test whether cross-clock *disagreement* adds signal
(gaps-analysis G1, Turn 01), or to score biological age for the Biolearn leaderboard.

## Install
```bash
pip install pyaging # PyTorch-based; GPU optional but faster
```

## The workflow (pyaging's real API)
```python
import pyaging as pya
import pandas as pd

# 1. Load your data as a DataFrame (rows = samples, cols = features/CpGs), then -> AnnData.
# (EPICv2 arrays: aggregate probes first.)
# df = pya.pp.epicv2_probe_aggregation(df) # only for EPICv2
adata = pya.pp.df_to_adata(df, metadata_cols=["gender", "tissue_type", "dataset"],
imputer_strategy="knn")

# 2. Predict a PANEL of clocks in one call (170+ available; these are real clock names).
pya.pred.predict_age(adata, ["Horvath2013", "AltumAge", "PCGrimAge", "GrimAge2", "DunedinPACE"])

# 3. Read results — one column per clock in adata.obs; clock metadata in adata.uns.
print(adata.obs.head()) # predicted ages per sample, per clock
# adata.uns["Horvath2013_metadata"], adata.uns["<clock>_missing_features"]
```

## Hand off to the loop (why this skill exists)
Export the per-clock predicted ages and feed them to this repo's benchmark to get the
**cross-clock disagreement** number (the measurable core of G1):
```bash
# adata.obs[clock_cols] -> a CSV (rows = samples, header = clock names), then:
python3 scripts/clockbench.py --input clocks.csv
```
That closes the loop: pyaging (compute the panel) → clockbench (measure disagreement) → Turn 01.

## Discipline
Predicted ages are **computational estimates on your data** — label them as such and keep them
separate from any wet-lab/clinical claim. Verify the clock names against the current pyaging
ModelGallery (they evolve); `no evidence ⇒ no claim`.
54 changes: 54 additions & 0 deletions hub/pyaging/knowledge-graph.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"schema": "longevity-loop hub knowledge graph — portable nodes/edges JSON",
"source": {
"repo": "rsinghlab/pyaging",
"url": "https://github.com/rsinghlab/pyaging",
"sha": "c2b3000e3c2c",
"grounded_in": "repo README + pyaging.readthedocs.io tutorials (verbatim API)"
},
"nodes": [
{"id": "repo:pyaging", "label": "pyaging", "type": "repo", "note": "170+ GPU-optimized aging clocks; BSD-3"},
{"id": "mod:pp", "label": "pya.pp", "type": "module", "note": "preprocessing / data prep"},
{"id": "mod:pred", "label": "pya.pred", "type": "module", "note": "clock prediction"},
{"id": "mod:data", "label": "pya.data", "type": "module", "note": "example data / loaders"},
{"id": "fn:df_to_adata", "label": "pya.pp.df_to_adata", "type": "function", "note": "DataFrame -> AnnData (metadata_cols, imputer_strategy='knn')"},
{"id": "fn:epicv2", "label": "pya.pp.epicv2_probe_aggregation", "type": "function", "note": "EPICv2 probe aggregation"},
{"id": "fn:predict_age", "label": "pya.pred.predict_age", "type": "function", "note": "predict_age(adata, [clock_names]) -> results in adata.obs"},
{"id": "concept:anndata", "label": "AnnData", "type": "concept", "note": "the core data container"},
{"id": "concept:clock", "label": "aging clock (170+)", "type": "concept"},
{"id": "clock:Horvath2013", "label": "Horvath2013", "type": "clock"},
{"id": "clock:AltumAge", "label": "AltumAge", "type": "clock"},
{"id": "clock:PCGrimAge", "label": "PCGrimAge", "type": "clock"},
{"id": "clock:GrimAge2", "label": "GrimAge2", "type": "clock"},
{"id": "clock:DunedinPACE", "label": "DunedinPACE", "type": "clock"},
{"id": "modality:dnam", "label": "DNA methylation", "type": "modality"},
{"id": "modality:rna", "label": "RNA-seq", "type": "modality"},
{"id": "modality:atac", "label": "ATAC-seq", "type": "modality"},
{"id": "modality:histone", "label": "histone marks", "type": "modality"},
{"id": "modality:chem", "label": "blood chemistry", "type": "modality"},
{"id": "ext:clockbench", "label": "longevity-loop clockbench (G1)", "type": "downstream", "note": "consumes the clock panel to measure cross-clock disagreement"}
],
"edges": [
{"source": "repo:pyaging", "target": "mod:pp", "rel": "contains"},
{"source": "repo:pyaging", "target": "mod:pred", "rel": "contains"},
{"source": "repo:pyaging", "target": "mod:data", "rel": "contains"},
{"source": "mod:pp", "target": "fn:df_to_adata", "rel": "defines"},
{"source": "mod:pp", "target": "fn:epicv2", "rel": "defines"},
{"source": "mod:pred", "target": "fn:predict_age", "rel": "defines"},
{"source": "fn:df_to_adata", "target": "concept:anndata", "rel": "produces"},
{"source": "fn:predict_age", "target": "concept:anndata", "rel": "consumes"},
{"source": "fn:predict_age", "target": "concept:clock", "rel": "predicts"},
{"source": "clock:Horvath2013", "target": "concept:clock", "rel": "is-a"},
{"source": "clock:AltumAge", "target": "concept:clock", "rel": "is-a"},
{"source": "clock:PCGrimAge", "target": "concept:clock", "rel": "is-a"},
{"source": "clock:GrimAge2", "target": "concept:clock", "rel": "is-a"},
{"source": "clock:DunedinPACE", "target": "concept:clock", "rel": "is-a"},
{"source": "repo:pyaging", "target": "modality:dnam", "rel": "supports"},
{"source": "repo:pyaging", "target": "modality:rna", "rel": "supports"},
{"source": "repo:pyaging", "target": "modality:atac", "rel": "supports"},
{"source": "repo:pyaging", "target": "modality:histone", "rel": "supports"},
{"source": "repo:pyaging", "target": "modality:chem", "rel": "supports"},
{"source": "fn:predict_age", "target": "ext:clockbench", "rel": "feeds"}
],
"counts": {"nodes": 20, "edges": 20}
}
16 changes: 16 additions & 0 deletions hub/pyaging/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"repo": "rsinghlab/pyaging",
"url": "https://github.com/rsinghlab/pyaging",
"source_sha": "c2b3000e3c2c",
"generated_at": "2026-07-19",
"license": "BSD-3-Clause",
"stars_at_generation": 127,
"one_line": "A Python compendium of GPU-optimized biological aging clocks (170+ published clocks).",
"artifacts": ["knowledge-graph.json", "SKILL.md"],
"engines": {
"knowledge_graph": "grounded from the pyaging repo + readthedocs (production: graphify / understand-anything)",
"skill": "grounded from the pyaging real API (production: anyagent reverse -> refine)"
},
"provenance_note": "Every fact is grounded in the pyaging repo/docs at source_sha. This is the Phase-2 exemplar of the JIT deep layer (docs/HUB_ARCHITECTURE.md): regenerate when source_sha changes — `scripts/hub_gen.py --refresh` flags staleness. No evidence => no claim.",
"why": "pyaging computes the epigenetic-clock panel that feeds scripts/clockbench.py (gaps-analysis G1) and Turn 01 — the loop's #1 measurement target."
}
4 changes: 3 additions & 1 deletion scripts/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ def render_readme() -> str:
"Design (high-quality · fast · cheap · fresh · future-proof): "
"**[docs/HUB_ARCHITECTURE.md](docs/HUB_ARCHITECTURE.md)** · per-repo generation recipes: "
"**[docs/REPOS.md](docs/REPOS.md)**. Fresh index, just-in-time depth — deep artifacts are "
"generated on demand and cached by commit SHA, never committed stale.", "", "---", ""]
"generated on demand and cached by commit SHA, never committed stale. First deep exemplar "
"(Phase 2): **[hub/pyaging](hub/pyaging)** — a grounded knowledge graph + a gated skill, "
"SHA-stamped, with a live staleness check (`make hub` / `scripts/hub_gen.py --refresh`).", "", "---", ""]

# What we're shooting (static pointer to the problem map)
L += ['<h2 id="target">🎯 What we\'re shooting</h2>', "",
Expand Down
Loading
Loading