amarantos 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,13 @@
1
+ """Load choice data from YAML files."""
2
+
3
+ from amarantos.core.schemas import CHOICES_DIR, Choice
4
+
5
+
6
+ def load_all_choices(domain: str | None = None) -> list[Choice]:
7
+ """Load all choices, optionally filtered by domain."""
8
+ if domain:
9
+ paths = sorted((CHOICES_DIR / domain).glob("*.yaml"))
10
+ else:
11
+ paths = sorted(CHOICES_DIR.glob("**/*.yaml"))
12
+
13
+ return [Choice.load(path) for path in paths]
@@ -0,0 +1,156 @@
1
+ """Schemas for choice data and user profiles."""
2
+
3
+ import re
4
+ from enum import StrEnum
5
+ from pathlib import Path
6
+
7
+ import attrs
8
+ import dummio.yaml
9
+
10
+ DATA_DIR = Path(__file__).parent.parent.parent / "data"
11
+ CHOICES_DIR = DATA_DIR / "choices"
12
+
13
+ # 95% CI uses 1.96 standard deviations
14
+ Z_95 = 1.96
15
+
16
+
17
+ def _name_to_filename(name: str) -> str:
18
+ """Convert a choice name to a valid filename."""
19
+ clean = name.lower()
20
+ clean = re.sub(r"\s*\([^)]*\)", "", clean) # Remove parentheses content
21
+ clean = re.sub(r"[^a-z0-9]+", "_", clean) # Replace non-alphanumeric with _
22
+ return clean.strip("_") + ".yaml"
23
+
24
+
25
+ class Outcome(StrEnum):
26
+ """Health outcomes that can be measured -- at least in principle -- on a continuous scale."""
27
+
28
+ RELATIVE_MORTALITY_RISK = "Relative mortality risk"
29
+ DELAYED_AGING = "Years of delayed aging"
30
+ SUBJECTIVE_WELLBEING = "Subjective wellbeing - number of just-noticeable differences"
31
+
32
+
33
+ @attrs.frozen
34
+ class Effect:
35
+ """A Gaussian-distributed health effect estimate.
36
+
37
+ Attributes:
38
+ outcome: The health outcome being measured.
39
+ evidence: A summary of the evidence supporting this effect. Open-ended, but ideally includes things such as
40
+ the nature of the studies, sample sizes, and any relevant statistical measures, or first-principles
41
+ reasoning.
42
+ mean: The mean effect estimate.
43
+ std: The standard deviation of the effect estimate.
44
+ """
45
+
46
+ outcome: Outcome
47
+ mean: float
48
+ std: float
49
+ evidence: str = ""
50
+
51
+ @property
52
+ def ci_lower(self) -> float:
53
+ """Lower bound of 95% confidence interval."""
54
+ return self.mean - Z_95 * self.std
55
+
56
+ @property
57
+ def ci_upper(self) -> float:
58
+ """Upper bound of 95% confidence interval."""
59
+ return self.mean + Z_95 * self.std
60
+
61
+ @property
62
+ def is_beneficial(self) -> bool:
63
+ """Effect is beneficial if upper bound < 1.0."""
64
+ return self.ci_upper < 1.0
65
+
66
+ @property
67
+ def is_harmful(self) -> bool:
68
+ """Effect is harmful if lower bound > 1.0."""
69
+ return self.ci_lower > 1.0
70
+
71
+ @property
72
+ def is_uncertain(self) -> bool:
73
+ """Effect is uncertain if CI crosses 1.0."""
74
+ return self.ci_lower < 1.0 < self.ci_upper
75
+
76
+
77
+ @attrs.frozen
78
+ class Specification:
79
+ """Detailed specification of a wellness choice.
80
+
81
+ Attributes:
82
+ duration_h: Average duration of one session of the activity in hours.
83
+ For running, ~0.5. For taking a pill, ~0.001.
84
+ weekly_freq: How many times per week on average. Running might be 4,
85
+ taking a pill might be 7, fasting might be 1.
86
+ annual_cost_h: Total annual time cost including preparation, cleanup,
87
+ and actually doing the activity. Sleep optimization should count
88
+ bedtime ritual plus extra sleep time.
89
+ annual_cost_usd: Total annual dollar cost excluding time. For running,
90
+ maybe $100 for shoes.
91
+ description: Plain english description of the choice noting common
92
+ variations in implementation and citing evidence where available.
93
+ """
94
+
95
+ duration_h: float
96
+ weekly_freq: float
97
+ annual_cost_h: float
98
+ annual_cost_usd: float
99
+ description: str = ""
100
+
101
+
102
+ @attrs.frozen
103
+ class Choice:
104
+ """A wellness choice with effect estimates."""
105
+
106
+ domain: str
107
+ name: str
108
+ effects: tuple[Effect, ...]
109
+ specification: Specification
110
+ summary: str = ""
111
+
112
+ @property
113
+ def path(self) -> Path:
114
+ """Default path for this choice."""
115
+ return CHOICES_DIR / self.domain / _name_to_filename(self.name)
116
+
117
+ @classmethod
118
+ def load(cls, path: Path) -> "Choice":
119
+ """Load a choice from a YAML file."""
120
+ data = dummio.yaml.load(filepath=path)
121
+ data["effects"] = tuple(Effect(**e) for e in data["effects"])
122
+ data["specification"] = Specification(**data["specification"])
123
+ data.pop("literature", None) # Remove legacy field if present
124
+ data.pop("annual_cost", None) # Remove legacy field if present
125
+ return cls(**data)
126
+
127
+ def save(self, path: Path | None = None) -> None:
128
+ """Save this choice to a YAML file."""
129
+ if path is None:
130
+ path = self.path
131
+ data = {
132
+ "domain": self.domain,
133
+ "name": self.name,
134
+ "specification": attrs.asdict(self.specification),
135
+ "effects": [attrs.asdict(e) for e in self.effects],
136
+ }
137
+ if self.summary:
138
+ data["summary"] = self.summary
139
+ dummio.yaml.save(data, filepath=path)
140
+
141
+
142
+ @attrs.frozen
143
+ class User:
144
+ """User attributes for personalized recommendations."""
145
+
146
+ is_male: bool | None = None
147
+ age: int | None = None
148
+ height_cm: float | None = None
149
+ body_fat_pct: float | None = None
150
+ blood_pressure_systolic: int | None = None
151
+ is_vegan: bool | None = None
152
+ is_vegetarian: bool | None = None
153
+ diet_quality_pctl: float | None = None
154
+ exercise_cardio_pctl: float | None = None
155
+ exercise_resistance_pctl: float | None = None
156
+ sleep_hours: float | None = None
amarantos/rank.py ADDED
@@ -0,0 +1,101 @@
1
+ """CLI to rank wellness choices by conservative lifespan impact estimate."""
2
+
3
+ import click
4
+
5
+ from amarantos.core.loaders import load_all_choices
6
+ from amarantos.core.schemas import Choice, Effect, Outcome
7
+
8
+ # 30th percentile z-score for normal distribution
9
+ Z_30 = -0.524
10
+
11
+
12
+ def get_effect_by_outcome(choice: Choice, outcome: Outcome) -> Effect | None:
13
+ """Extract a specific effect from a choice by outcome type."""
14
+ for effect in choice.effects:
15
+ if effect.outcome == outcome:
16
+ return effect
17
+ return None
18
+
19
+
20
+ def percentile_30(effect: Effect) -> float:
21
+ """Calculate 30th percentile of effect estimate."""
22
+ return effect.mean + Z_30 * effect.std
23
+
24
+
25
+ @click.command()
26
+ @click.option(
27
+ "-n",
28
+ "--num-top-bottom",
29
+ type=int,
30
+ default=None,
31
+ help="Show only top N and bottom N choices",
32
+ )
33
+ @click.option(
34
+ "-d",
35
+ "--domain",
36
+ type=str,
37
+ default=None,
38
+ help="Filter by domain (e.g., 'diet', 'exercise')",
39
+ )
40
+ @click.option(
41
+ "--maxd",
42
+ type=int,
43
+ default=None,
44
+ help="Show only top N choices from each domain",
45
+ )
46
+ def main(num_top_bottom: int | None, domain: str | None, maxd: int | None) -> None:
47
+ """Rank wellness choices by 30th percentile lifespan impact."""
48
+ choices = load_all_choices(domain)
49
+
50
+ results: list[tuple[str, str, float, float, float]] = []
51
+ for choice in choices:
52
+ aging_effect = get_effect_by_outcome(choice, Outcome.DELAYED_AGING)
53
+ if aging_effect:
54
+ p30 = percentile_30(aging_effect)
55
+ results.append(
56
+ (
57
+ choice.name,
58
+ choice.domain,
59
+ p30,
60
+ choice.specification.annual_cost_usd,
61
+ choice.specification.annual_cost_h,
62
+ )
63
+ )
64
+
65
+ # Sort by 30th percentile descending
66
+ results.sort(key=lambda x: x[2], reverse=True)
67
+
68
+ # Apply maxd filter if specified
69
+ if maxd is not None:
70
+ domain_counts: dict[str, int] = {}
71
+ filtered: list[tuple[str, str, float, float, float]] = []
72
+ for item in results:
73
+ d = item[1]
74
+ domain_counts[d] = domain_counts.get(d, 0) + 1
75
+ if domain_counts[d] <= maxd:
76
+ filtered.append(item)
77
+ results = filtered
78
+
79
+ # Header
80
+ click.echo()
81
+ click.echo(f"{'Choice':<40} {'P30 (years)':>12} {'$/year':>10} {'h/year':>10}")
82
+ click.echo("-" * 74)
83
+
84
+ if num_top_bottom is None:
85
+ for name, _, p30, cost_usd, cost_h in results:
86
+ click.echo(f"{name:<40} {p30:>+12.2f} {cost_usd:>10.0f} {cost_h:>10.0f}")
87
+ else:
88
+ click.echo(f"TOP {num_top_bottom}:")
89
+ for name, _, p30, cost_usd, cost_h in results[:num_top_bottom]:
90
+ click.echo(f"{name:<40} {p30:>+12.2f} {cost_usd:>10.0f} {cost_h:>10.0f}")
91
+
92
+ click.echo()
93
+ click.echo(f"BOTTOM {num_top_bottom}:")
94
+ for name, _, p30, cost_usd, cost_h in results[-num_top_bottom:]:
95
+ click.echo(f"{name:<40} {p30:>+12.2f} {cost_usd:>10.0f} {cost_h:>10.0f}")
96
+
97
+ click.echo()
98
+
99
+
100
+ if __name__ == "__main__":
101
+ main()
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.4
2
+ Name: amarantos
3
+ Version: 0.1.0
4
+ Summary: Tips and tools for personal wellness and longevity
5
+ Project-URL: Repository, https://github.com/zkurtz/amarantos
6
+ Author-email: Zach Kurtz <zkurtz@gmail.com>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Requires-Python: >=3.13
10
+ Requires-Dist: attrs>=25.4
11
+ Requires-Dist: click>=8.3.1
12
+ Requires-Dist: dummio>=1.10.2
13
+ Requires-Dist: matplotlib>=3.10.8
14
+ Requires-Dist: numpy>=2.2.6
15
+ Requires-Dist: pre-commit>=4.0.1
16
+ Requires-Dist: ruamel-yaml>=0.19.1
17
+ Description-Content-Type: text/markdown
18
+
19
+ # Amarantos
20
+
21
+ Tips and tools for personal wellness and longevity. *Amarantos* (ἀμάραντος) is Greek for "unfading" or "immortal" and is the root of *amaranth*—a flower known for retaining its color even dried.
22
+
23
+ > **Warning: AI-Generated Content**
24
+ >
25
+ > This repository was generated with AI assistance and has not been thoroughly vetted by a human. References, claims, and code may contain errors or inaccuracies. Please double-check all information against primary sources and exercise critical judgment. Treat this as a starting point for careful research, not a definitive resource.
26
+
27
+ ## CLI Commands
28
+
29
+ ```bash
30
+ # Rank all choices by 30th percentile lifespan impact
31
+ amarantos
32
+
33
+ # Filter by domain
34
+ amarantos --domain exercise
35
+
36
+ # Show only top/bottom 5
37
+ amarantos -n 5
38
+
39
+ # Show top 3 from each domain
40
+ amarantos --maxd 3
41
+ ```
42
+
43
+ ## Awesome Longevity Resources
44
+
45
+ A curated list of products, tools, and resources for personal wellness and longevity.
46
+
47
+ ### Knowledge & Research
48
+
49
+ - [Examine.com](https://examine.com/) - Evidence-based supplement and nutrition information
50
+ - [Peter Attia's The Drive](https://peterattiamd.com/) - Longevity-focused podcast and resources
51
+ - [FoundMyFitness](https://www.foundmyfitness.com/) - Dr. Rhonda Patrick's research on nutrition and aging
52
+ - [Fight Aging!](https://www.fightaging.org/) - Long-running blog covering aging research news
53
+ - [LongevityWiki](https://longevitywiki.org/) - Community-curated longevity information
54
+ - [Longevity Protocols](https://longevity-protocols.com/) - Personal project with AI-analyzed interventions (not peer-reviewed)
55
+ - [Bryan Johnson's Blueprint](https://blueprint.bryanjohnson.com/) - Detailed self-experimentation protocol (note: sells supplements)
56
+
57
+ ### Scientific Databases & Journals
58
+
59
+ - [DrugAge Database](https://genomics.senescence.info/drugs/) - Database of aging-related drugs
60
+ - [Human Ageing Genomic Resources](https://genomics.senescence.info/) - Databases on aging-related genes
61
+ - [GeroScience](https://www.springer.com/journal/11357) - Peer-reviewed aging research journal
62
+
63
+ ### Communities & DAOs
64
+
65
+ - [r/longevity](https://www.reddit.com/r/longevity/) - Reddit community for longevity research
66
+ - [VitaDAO](https://www.vitadao.com/) - Decentralized collective funding longevity research
67
+ - [LessWrong Longevity Tag](https://www.lesswrong.com/tag/life-extension) - Rationalist perspectives on life extension
68
+
69
+ ### GitHub Repos & Awesome Lists
70
+
71
+ - [awesome-longevity (atilatech)](https://github.com/atilatech/awesome-longevity) - Comprehensive longevity resources list
72
+ - [awesome-longevity (Rejuve)](https://github.com/Rejuve/awesome-longevity) - Therapeutics, regenerative medicine, medical AI
73
+ - [awesome-longevity-information](https://github.com/Laurentiu-Andronache/awesome-longevity-information) - Curated healthspan extension resources
74
+ - [longevityTools](https://github.com/tgirke/longevityTools) - R package for longevity research analysis
75
+ - [Longevity Genie](https://github.com/longevity-genie) - Open-source AI tools for longevity research
76
+
77
+ ### Tracking & Measurement
78
+
79
+ - [Oura Ring](https://ouraring.com/) - Sleep and activity tracking
80
+ - [Levels](https://www.levels.com/) - Continuous glucose monitoring
81
+ - [InsideTracker](https://www.insidetracker.com/) - Blood biomarker analysis
82
+ - [WHOOP](https://www.whoop.com/) - Strain and recovery monitoring
83
+
84
+ ### Academic & Research Institutions
85
+
86
+ - [National Institute on Aging (NIA)](https://www.nia.nih.gov/) - NIH's primary aging research arm
87
+ - [Buck Institute for Research on Aging](https://www.buckinstitute.org/) - Leading independent aging research institute
88
+ - [Lifespan Research Institute (formerly SENS)](https://www.sens.org/) - Nonprofit focused on damage-repair approaches to aging
89
+ - [Altos Labs](https://www.altoslabs.com/) - Well-funded cellular reprogramming research
90
+ - [Calico Labs](https://www.calicolabs.com/) - Google/Alphabet's aging research company
91
+ - [Stanford Center on Longevity](https://longevity.stanford.edu/) - Interdisciplinary longevity research
92
+ - [American Federation for Aging Research (AFAR)](https://www.afar.org/) - Funds aging research and education
93
+
94
+ ## Software Tools
95
+
96
+ ### Installating amarantos
97
+
98
+ TODO: get on pypi.
99
+
100
+ ```bash
101
+ uv add amarantos
102
+ ```
103
+
104
+ ## Usage
105
+
106
+ ```python
107
+ import amarantos
108
+
109
+ amarantos.hello()
110
+ ```
111
+
112
+ TODO: build something!
@@ -0,0 +1,8 @@
1
+ amarantos/rank.py,sha256=zRPcrmLM0DmWbpyny3cIDiLS1grnN3vDjAzQV5KbKMI,3080
2
+ amarantos/core/loaders.py,sha256=cjP3ZonnEiih_AVRhduxj7M9JUA5aKYIkwEAC6zCD54,413
3
+ amarantos/core/schemas.py,sha256=VB2635pK7v_ImH-CiTHOoDQt8HsgCX2j6iOpBjONLv0,5043
4
+ amarantos-0.1.0.dist-info/METADATA,sha256=SmidSvIaAReZGrjslppQgIE4YXDMZ_pnuGXR3btzctY,4828
5
+ amarantos-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
6
+ amarantos-0.1.0.dist-info/entry_points.txt,sha256=q8v2iCpAqD4w2NvptbQCsvdUQhq0yge1WyPaxNOdlwg,50
7
+ amarantos-0.1.0.dist-info/licenses/LICENSE,sha256=yYmJX4hIj1EvCSZdWf20KULynADt84gULi3-Pqkb5l8,1067
8
+ amarantos-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ amarantos = amarantos.rank:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zach Kurtz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.