dearnana 0.1.0__tar.gz

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.
Files changed (41) hide show
  1. dearnana-0.1.0/.env.example +1 -0
  2. dearnana-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +34 -0
  3. dearnana-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +15 -0
  4. dearnana-0.1.0/.github/dependabot.yml +10 -0
  5. dearnana-0.1.0/.github/pull_request_template.md +8 -0
  6. dearnana-0.1.0/.github/workflows/ci.yml +26 -0
  7. dearnana-0.1.0/.github/workflows/release.yml +39 -0
  8. dearnana-0.1.0/.gitignore +16 -0
  9. dearnana-0.1.0/CONTRIBUTING.md +65 -0
  10. dearnana-0.1.0/DISCLAIMER.md +65 -0
  11. dearnana-0.1.0/LICENSE +21 -0
  12. dearnana-0.1.0/PKG-INFO +337 -0
  13. dearnana-0.1.0/README.md +309 -0
  14. dearnana-0.1.0/pyproject.toml +49 -0
  15. dearnana-0.1.0/src/dearnana/__init__.py +46 -0
  16. dearnana-0.1.0/src/dearnana/cli.py +368 -0
  17. dearnana-0.1.0/src/dearnana/cms_client.py +445 -0
  18. dearnana-0.1.0/src/dearnana/comparison.py +44 -0
  19. dearnana-0.1.0/src/dearnana/condition.py +181 -0
  20. dearnana-0.1.0/src/dearnana/config.py +96 -0
  21. dearnana-0.1.0/src/dearnana/errors.py +8 -0
  22. dearnana-0.1.0/src/dearnana/export.py +155 -0
  23. dearnana-0.1.0/src/dearnana/geocode.py +111 -0
  24. dearnana-0.1.0/src/dearnana/llm.py +136 -0
  25. dearnana-0.1.0/src/dearnana/llm_advisor.py +171 -0
  26. dearnana-0.1.0/src/dearnana/models.py +72 -0
  27. dearnana-0.1.0/src/dearnana/questionnaire.py +57 -0
  28. dearnana-0.1.0/src/dearnana/ranker.py +268 -0
  29. dearnana-0.1.0/src/dearnana/report.py +257 -0
  30. dearnana-0.1.0/tests/conftest.py +30 -0
  31. dearnana-0.1.0/tests/test_audit_fixes.py +127 -0
  32. dearnana-0.1.0/tests/test_cms_client.py +156 -0
  33. dearnana-0.1.0/tests/test_comparison.py +44 -0
  34. dearnana-0.1.0/tests/test_condition.py +154 -0
  35. dearnana-0.1.0/tests/test_export.py +66 -0
  36. dearnana-0.1.0/tests/test_geocode.py +62 -0
  37. dearnana-0.1.0/tests/test_llm.py +87 -0
  38. dearnana-0.1.0/tests/test_llm_advisor.py +112 -0
  39. dearnana-0.1.0/tests/test_questionnaire.py +32 -0
  40. dearnana-0.1.0/tests/test_ranker.py +248 -0
  41. dearnana-0.1.0/tests/test_report.py +99 -0
@@ -0,0 +1 @@
1
+ ANTHROPIC_API_KEY=sk-ant-...
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: Bug report
3
+ about: Something isn't working
4
+ labels: bug
5
+ ---
6
+
7
+ **What happened?**
8
+
9
+ A clear description of the bug.
10
+
11
+ **Command you ran**
12
+
13
+ ```bash
14
+ # Paste your dearnana command — feel free to replace your address with a generic
15
+ # city/zip (e.g. "Bellevue, WA 98008") if you don't want to share it.
16
+ dearnana --address "..." --budget ... --condition "..."
17
+ ```
18
+
19
+ - Were you using `--no-ai`? (yes/no)
20
+ - Was `ANTHROPIC_API_KEY` set? (yes/no — never paste the key itself)
21
+
22
+ **Expected behavior**
23
+
24
+ **Actual behavior / error output**
25
+
26
+ ```
27
+ paste the traceback or wrong output here
28
+ ```
29
+
30
+ **Environment**
31
+
32
+ - OS:
33
+ - Python version (`python --version`):
34
+ - dearnana version (`pip show dearnana`):
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an improvement
4
+ labels: enhancement
5
+ ---
6
+
7
+ **What problem would this solve?**
8
+
9
+ Describe the situation — e.g. "When searching near a state border, facilities across the line don't show up."
10
+
11
+ **Proposed solution**
12
+
13
+ **Alternatives considered**
14
+
15
+ **Note for scoring-related requests:** changes to the ranking methodology need a rationale and a before/after comparison — see [CONTRIBUTING.md](../../CONTRIBUTING.md#changing-the-scoring-methodology).
@@ -0,0 +1,10 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: pip
4
+ directory: "/"
5
+ schedule:
6
+ interval: weekly
7
+ - package-ecosystem: github-actions
8
+ directory: "/"
9
+ schedule:
10
+ interval: weekly
@@ -0,0 +1,8 @@
1
+ ## What does this PR do?
2
+
3
+ ## Checklist
4
+
5
+ - [ ] `pytest` passes locally (no API key needed — LLM calls are mocked)
6
+ - [ ] New behavior has tests
7
+ - [ ] README/docs updated if user-facing behavior changed
8
+ - [ ] **If this touches scoring** (`WEIGHTS`, `ranker.py` scorers, `condition.py` measure map): rationale + before/after comparison included per [CONTRIBUTING.md](../CONTRIBUTING.md#changing-the-scoring-methodology)
@@ -0,0 +1,26 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ test:
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ python-version: ["3.11", "3.12", "3.13"]
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ - uses: actions/setup-python@v6
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+ - name: Install package with dev dependencies
24
+ run: pip install -e ".[dev]"
25
+ - name: Run tests
26
+ run: pytest -v
@@ -0,0 +1,39 @@
1
+ name: Release to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: actions/setup-python@v6
16
+ with:
17
+ python-version: "3.12"
18
+ - name: Build sdist and wheel
19
+ run: |
20
+ pip install build
21
+ python -m build
22
+ - uses: actions/upload-artifact@v7
23
+ with:
24
+ name: dist
25
+ path: dist/
26
+
27
+ publish:
28
+ needs: build
29
+ runs-on: ubuntu-latest
30
+ environment: pypi
31
+ permissions:
32
+ id-token: write # required for PyPI trusted publishing
33
+ steps:
34
+ - uses: actions/download-artifact@v8
35
+ with:
36
+ name: dist
37
+ path: dist/
38
+ - name: Publish to PyPI
39
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,16 @@
1
+ .env
2
+ .env.*
3
+ !.env.example
4
+
5
+ __pycache__/
6
+ *.pyc
7
+ *.egg-info/
8
+ dist/
9
+ build/
10
+
11
+ .dearnana/
12
+ reports/
13
+ dearnana-reports/
14
+
15
+ .venv/
16
+ venv/
@@ -0,0 +1,65 @@
1
+ # Contributing to DearNana
2
+
3
+ Thanks for helping make nursing home data more transparent. Issues and PRs are welcome.
4
+
5
+ ## Development setup
6
+
7
+ ```bash
8
+ git clone https://github.com/miaomiaocui/dearnana
9
+ cd dearnana
10
+ python -m venv .venv && source .venv/bin/activate
11
+ pip install -e ".[dev]"
12
+ ```
13
+
14
+ Requires Python 3.11+.
15
+
16
+ ## Running tests
17
+
18
+ ```bash
19
+ pytest
20
+ ```
21
+
22
+ **No API key is needed for the test suite** — all Anthropic API calls are mocked. The tests also make no network calls to CMS or Nominatim.
23
+
24
+ To smoke-test against live data without any API cost:
25
+
26
+ ```bash
27
+ dearnana --address "Bellevue, WA 98008" --budget 8000 \
28
+ --condition "moderate dementia, has fallen twice" --no-ai
29
+ ```
30
+
31
+ CMS responses are cached for 24h under `~/.dearnana/cache`, so repeat runs are fast and gentle on the API.
32
+
33
+ ## Bringing your own API key
34
+
35
+ The AI features (condition parsing + recommendation report) require an Anthropic API key. Get one at [console.anthropic.com](https://console.anthropic.com) and either export `ANTHROPIC_API_KEY` or copy `.env.example` to `.env`. Everything else works without one.
36
+
37
+ ## Changing the scoring methodology
38
+
39
+ Scoring changes affect real families making high-stakes decisions, so they get extra scrutiny. A PR that touches `WEIGHTS`, the per-component scorers in `ranker.py`, the condition→measure map in `condition.py`, or any benchmark constant must include:
40
+
41
+ 1. **A rationale** — why is the new weighting/formula a better reflection of care quality? Cite evidence where possible (CMS technical docs, published research).
42
+ 2. **A before/after comparison** on a representative set of facilities (one full state is a good unit — Washington is the convention used so far). Report: how many facilities changed score, the mean/min/max delta, and the facilities with the largest moves. A small script against the cached state file is fine.
43
+ 3. **Updated documentation** — the README's "How Scores Are Calculated" section must stay in sync with the code.
44
+
45
+ Please also read [DISCLAIMER.md](DISCLAIMER.md) for known data-accuracy limitations before proposing changes.
46
+
47
+ ## Code conventions
48
+
49
+ - Pure scoring logic lives in `ranker.py` and must stay LLM-free and network-free.
50
+ - All CMS API access goes through `cms_client.py` (retry helper + file cache).
51
+ - All LLM access goes through the provider layer in `llm.py` (Anthropic API or local Ollama); providers return `None` on failure so callers can fall back.
52
+ - New CLI behavior needs a test; LLM interactions are tested with mocks (`pytest-mock`).
53
+ - Anything user-facing should degrade gracefully without an API key.
54
+
55
+ ## Releases (maintainers)
56
+
57
+ Publishing to PyPI uses GitHub Actions [trusted publishing](https://docs.pypi.org/trusted-publishers/) — no tokens are stored in the repo.
58
+
59
+ One-time setup: on pypi.org → your project (or "pending publisher" for the first release) → add a trusted publisher with repository `miaomiaocui/dearnana`, workflow `release.yml`, environment `pypi`.
60
+
61
+ To release:
62
+
63
+ 1. Bump `version` in `pyproject.toml` and `__version__` in `src/dearnana/__init__.py`
64
+ 2. Create a GitHub release with tag `vX.Y.Z`
65
+ 3. The `release.yml` workflow builds the sdist/wheel and publishes automatically
@@ -0,0 +1,65 @@
1
+ # DearNana — Disclaimers and Limitations
2
+
3
+ ---
4
+
5
+ ## 1. Not Medical or Legal Advice
6
+
7
+ DearNana is an informational tool that surfaces publicly available government data. It is **NOT** a substitute for professional medical advice, legal counsel, or in-person facility evaluation.
8
+
9
+ The composite score is a starting point for research — it is not a recommendation to place a family member in any specific facility. Nursing home selection is a complex, deeply personal decision that depends on factors well beyond what any dataset can capture.
10
+
11
+ Always consult qualified healthcare professionals (physicians, social workers, geriatric care managers) before making placement decisions. Always visit facilities in person and speak with staff and current residents' families before signing any agreement.
12
+
13
+ ---
14
+
15
+ ## 2. Data Source and Accuracy
16
+
17
+ - All facility data is sourced from the **CMS Provider Data Catalog** (https://data.cms.gov/provider-data/topics/nursing-homes), which CMS refreshes monthly.
18
+ - DearNana caches data locally for up to 24 hours to reduce API load — cached data may be up to 24 hours old at the time of your search.
19
+ - CMS data itself may lag real-world conditions by weeks to months, particularly for recent inspection findings, staffing changes, or newly levied penalties.
20
+ - DearNana does **not** independently verify CMS data. Errors, omissions, or outdated information in the CMS source will appear in DearNana output.
21
+ - **Facility costs** shown are state-level monthly medians for semi-private rooms from the CareScout (Genworth Financial) Cost of Care Survey 2024 (surveyed July–December 2024; https://www.carescout.com/cost-of-care). These are **not** facility-specific prices — actual costs vary significantly by facility, room type, and care level. Contact facilities directly for current rates. Many facilities accept Medicaid; eligibility is determined separately.
22
+
23
+ ---
24
+
25
+ ## 3. Scoring Methodology Limitations
26
+
27
+ - The composite score is based on **quantitative CMS metrics only**. It cannot capture subjective quality factors such as facility culture, staff warmth, food quality, activity programming, family communication practices, or the general environment.
28
+ - Scoring weights (e.g., 25% for overall rating, 20% for health inspections) are set by the DearNana project and represent one reasonable interpretation of available evidence. Reasonable people — including healthcare professionals — may weight these factors differently based on individual circumstances.
29
+ - Facilities with **missing data fields** receive a neutral score (50 out of 100) for those components. This may artificially inflate or deflate their overall ranking compared to fully-reported facilities.
30
+ - **Distance scoring** assumes that closer is generally preferable for family visits and continuity of care. This may not reflect your actual situation (e.g., if you prefer a specific facility farther away for clinical reasons).
31
+ - The **abuse flag deduction** (−50 points) is based on CMS's own abuse icon designation. DearNana applies this as a near-disqualifying penalty, which reflects the severity of the finding. However, the underlying CMS record should always be reviewed directly at https://www.medicare.gov/care-compare before drawing conclusions.
32
+
33
+ ---
34
+
35
+ ## 4. AI-Generated Recommendations
36
+
37
+ - When AI is enabled with the default provider (an `ANTHROPIC_API_KEY` is set and `--no-ai` is not used), DearNana sends your care condition description to the **Anthropic Claude API** twice: once to parse it into a structured needs profile that personalizes the ranking, and once to generate the personalized recommendation report.
38
+ - The condition description you provide is transmitted to Anthropic's servers and is subject to their privacy policy: https://www.anthropic.com/privacy
39
+ - You bring your own API key — DearNana never proxies your data through any server operated by the project. The only third parties contacted are CMS (facility data), OpenStreetMap Nominatim (geocoding your search address), and Anthropic (when AI is enabled with the default provider).
40
+ - **Local alternative:** with `DEARNANA_LLM_PROVIDER=ollama`, all AI processing runs on your own machine via a local model and your condition description is never transmitted to any AI provider. AI quality depends on the local model you choose.
41
+ - AI output is generated from the CMS data described above — it does not incorporate real-time information, facility-specific knowledge, or clinical assessment.
42
+ - AI-generated recommendations should be treated as a **structured summary of public data**, not a clinical assessment or professional referral.
43
+ - Use the `--no-ai` flag to skip all Anthropic API calls entirely. The ranked list — including condition-based personalization via built-in keyword matching — is still produced using CMS data only, and your condition description never leaves your machine.
44
+
45
+ ---
46
+
47
+ ## 5. No Financial Relationships
48
+
49
+ DearNana has no financial relationship with any nursing home, senior care network, placement service, referral agency, or healthcare organization. Facilities **cannot pay** to improve their scores or appear in results. Rankings are determined solely by the algorithm described in [README.md](README.md).
50
+
51
+ This tool was built to counter the opacity of for-profit referral networks that often steer families toward facilities that pay the highest referral fees rather than those that best fit their needs.
52
+
53
+ ---
54
+
55
+ ## 6. Liability
56
+
57
+ THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
58
+
59
+ THE AUTHORS AND CONTRIBUTORS OF DEARNANA DISCLAIM ALL LIABILITY FOR ANY DECISIONS, ACTIONS, OR OUTCOMES THAT RESULT FROM USE OF THIS TOOL OR RELIANCE ON ITS OUTPUT. THIS INCLUDES, WITHOUT LIMITATION, ANY HARM ARISING FROM NURSING HOME PLACEMENT DECISIONS INFORMED IN WHOLE OR IN PART BY DEARNANA'S SCORES, RANKINGS, OR AI-GENERATED REPORTS.
60
+
61
+ USE THIS TOOL AT YOUR OWN RISK. IT IS A STARTING POINT FOR RESEARCH — NOT A SUBSTITUTE FOR PROFESSIONAL ADVICE OR IN-PERSON EVALUATION.
62
+
63
+ ---
64
+
65
+ *Last updated: June 2026*
dearnana-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 DearNana Contributors
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.
@@ -0,0 +1,337 @@
1
+ Metadata-Version: 2.4
2
+ Name: dearnana
3
+ Version: 0.1.0
4
+ Summary: Find and rank nursing homes using CMS public data
5
+ Project-URL: Homepage, https://github.com/miaomiaocui/dearnana
6
+ Project-URL: Source, https://github.com/miaomiaocui/dearnana
7
+ Project-URL: Bug Tracker, https://github.com/miaomiaocui/dearnana/issues
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: CMS,healthcare,nursing home,senior care
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Requires-Python: >=3.11
18
+ Requires-Dist: anthropic>=0.78
19
+ Requires-Dist: click>=8.1
20
+ Requires-Dist: geopy>=2.4
21
+ Requires-Dist: httpx>=0.27
22
+ Requires-Dist: pydantic>=2.0
23
+ Requires-Dist: python-dotenv>=1.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest-mock>=3.14; extra == 'dev'
26
+ Requires-Dist: pytest>=8.0; extra == 'dev'
27
+ Description-Content-Type: text/markdown
28
+
29
+ # DearNana
30
+
31
+ **Find trustworthy nursing homes using CMS public data — not ads, not referrals.**
32
+
33
+ [![PyPI](https://img.shields.io/pypi/v/dearnana)](https://pypi.org/project/dearnana/)
34
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
35
+
36
+ ---
37
+
38
+ ## What It Does
39
+
40
+ DearNana searches the CMS (Centers for Medicare & Medicaid Services) public database of all Medicare/Medicaid certified nursing homes in the US and scores each facility on objective criteria derived entirely from government data. Your description of your loved one's care needs personalizes the ranking: it is matched against CMS's per-facility clinical quality measures (antipsychotic medication rates for dementia, falls with major injury for fall risk, pressure ulcers for wound care, and more). Each facility's ownership chain — and the chain's average track record — is surfaced alongside the score. No facility pays to be included, and no referral fees are ever involved. CMS refreshes the underlying datasets monthly.
41
+
42
+ **DearNana runs fully for free — no API key, no tokens.** AI is an optional final layer that rewrites the results into a plain-language report; everything else works the same with or without it.
43
+
44
+ ### Features
45
+
46
+ Works with **no API key, no tokens**:
47
+
48
+ - 🏥 **Quality ranking** of every certified nursing home near you, from objective CMS data
49
+ - 🎯 **Condition-aware personalization** — describe care needs in plain text, or build the profile with `--interactive` guided questions (no AI)
50
+ - 📋 **Detailed rule-based report** — per-facility strengths/weaknesses, automatically surfaced red flags (abuse flags, CMS Special Focus status, actual-harm citations, penalties, ownership changes), and concrete questions to ask on a tour
51
+ - 📊 **Side-by-side comparison table** of the top results in every run
52
+ - 🔎 **Filters** — `--min-stars`, `--exclude-abuse`, `--exclude-special-focus`, `--sprinkler-only`, `--independent-only`
53
+ - 💾 **Export & watchlist** — save results as CSV/HTML to share with family, and track picks across runs with a local watchlist
54
+
55
+ Optional, when you want it:
56
+
57
+ - 🤖 **AI-written recommendation** via the Anthropic API, or a **fully local** model through [Ollama](#run-fully-local-with-ollama) (nothing leaves your machine)
58
+
59
+ See [Using DearNana Without AI Tokens](#using-dearnana-without-ai-tokens) for a complete token-free workflow.
60
+
61
+ ---
62
+
63
+ ## Installation
64
+
65
+ ```bash
66
+ pip install dearnana
67
+ ```
68
+
69
+ Until the first PyPI release lands, install straight from GitHub:
70
+
71
+ ```bash
72
+ pip install git+https://github.com/miaomiaocui/dearnana
73
+ ```
74
+
75
+ **Requirements:**
76
+
77
+ - Python 3.11 or higher
78
+ - No API key required — DearNana works fully for free; see [Using DearNana Without AI Tokens](#using-dearnana-without-ai-tokens)
79
+ - For an AI-written recommendation (optional): set the `ANTHROPIC_API_KEY` environment variable (get a key at [console.anthropic.com](https://console.anthropic.com))
80
+ - Use `--no-ai` (or just leave the key unset) to get a detailed rule-based report instead — ranking and condition personalization still work using CMS data only
81
+
82
+ **Optional environment variables:**
83
+
84
+ | Variable | Default | Purpose |
85
+ |----------|---------|---------|
86
+ | `DEARNANA_REPORTS_DIR` | `./dearnana-reports` | Where markdown reports are written |
87
+ | `DEARNANA_LLM_PROVIDER` | `anthropic` | `anthropic` (API key required) or `ollama` (local models) |
88
+ | `DEARNANA_LLM_MODEL` | `claude-sonnet-4-6` / `llama3.1:8b` | Model for the recommendation report (default depends on provider) |
89
+ | `DEARNANA_PARSER_MODEL` | `claude-haiku-4-5` / same as LLM model | Model for condition parsing |
90
+ | `DEARNANA_OLLAMA_HOST` | `http://localhost:11434` | Ollama server address |
91
+
92
+ ---
93
+
94
+ ## Run Fully Local with Ollama
95
+
96
+ Prefer not to send anything to a cloud API? DearNana can use a local model
97
+ via [Ollama](https://ollama.com) — **the care-needs description never leaves
98
+ your machine** (the only network calls are to CMS for facility data and
99
+ OpenStreetMap for geocoding your search address):
100
+
101
+ ```bash
102
+ ollama pull llama3.1:8b
103
+
104
+ export DEARNANA_LLM_PROVIDER=ollama
105
+ dearnana --address "Bellevue, WA 98008" --budget 8000 \
106
+ --condition "Mom has moderate dementia and has fallen twice"
107
+ ```
108
+
109
+ No API key needed. Pick any model you have pulled with `DEARNANA_LLM_MODEL`
110
+ (e.g. `llama3.1:70b`, `qwen2.5:14b`).
111
+
112
+ **Quality note:** local model output quality varies widely by model and
113
+ size — expect smaller models (e.g. 8B) to produce more generic
114
+ recommendation reports than the cloud default. Try a couple of models you
115
+ can run and compare. The condition-parsing step works well even on small
116
+ models, and if the model fails or Ollama isn't running, DearNana degrades
117
+ gracefully to keyword-based personalization and the data-only ranking.
118
+
119
+ ---
120
+
121
+ ## Quick Start (CLI)
122
+
123
+ ```bash
124
+ dearnana \
125
+ --address "Bellevue, WA 98008" \
126
+ --budget 8000 \
127
+ --condition "Mom has moderate dementia, needs memory care and mobility assistance" \
128
+ --radius 25 \
129
+ --top 5
130
+ ```
131
+
132
+ **Flag reference:**
133
+
134
+ | Flag | Required | Description |
135
+ |------|----------|-------------|
136
+ | `--address` | Yes | US address or city/zip to search near |
137
+ | `--budget` | Yes | Monthly budget in dollars |
138
+ | `--condition` | Yes* | Description of care needs — personalizes the ranking and the report (*optional with `--interactive`) |
139
+ | `--interactive` | No | Answer guided questions to build the needs profile — no AI, nothing leaves your computer |
140
+ | `--radius` | No | Search radius in miles (default: 50) |
141
+ | `--top` | No | Number of results to show (default: 5) |
142
+ | `--no-ai` | No | Skip the AI call; produce a detailed **rule-based** report instead |
143
+ | `--min-stars` | No | Only include facilities with at least this CMS overall rating (1–5) |
144
+ | `--exclude-abuse` | No | Exclude facilities flagged for abuse/neglect |
145
+ | `--exclude-special-focus` | No | Exclude CMS Special Focus facilities |
146
+ | `--sprinkler-only` | No | Only include facilities with full sprinkler coverage |
147
+ | `--independent-only` | No | Exclude chain-affiliated facilities |
148
+ | `--export csv\|html` | No | Also write results as a CSV or HTML file next to the report |
149
+ | `--save-watchlist` | No | Save the top picks to a local watchlist (`~/.dearnana/watchlist.json`) |
150
+ | `--show-watchlist` | No | Print your saved watchlist and exit |
151
+
152
+ **Example output (real run, June 2026, abbreviated):**
153
+
154
+ ```
155
+ Geocoding: Bellevue, WA 98008
156
+ -> (47.5851, -122.1470) in WA
157
+ Personalizing for: dementia / memory care (long-stay antipsychotic use, ...);
158
+ fall risk (falls with major injury, ...) — parsed via keyword matching
159
+ Fetching nursing homes in WA...
160
+ -> 194 facilities found (2 not yet rated by CMS)
161
+ Fetching care quality measures for WA...
162
+ Ranking within 25.0 miles...
163
+
164
+ --- DearNana Top 5 ---
165
+
166
+ #1. COVENANT SHORES HEALTH CENTER
167
+ 9107 FORTUNA DRIVE, MERCER ISLAND, WA 98040
168
+ 3.0 mi | Score: 86.1/100 | CMS: 5/5 | Phone: 2063168042
169
+ Chain: COVENANT LIVING (15 facilities, avg 4.3/5)
170
+ long-stay antipsychotic use: 10.3% vs state median 14.0% (better than 75% of WA facilities)
171
+ falls with major injury: 0.0% vs state median 2.3% (better than 100% of WA facilities)
172
+
173
+ At a glance:
174
+
175
+ | # | Facility | Dist | Score | CMS | Staffing | Turnover | Penalties | Abuse | Chain |
176
+ | - | ----------------------------- | ------- | ----- | --- | -------- | -------- | --------- | ----- | --------------- |
177
+ | 1 | COVENANT SHORES HEALTH CENTER | 3.0 mi | 86.1 | 5/5 | 5/5 | 49% | 0 | — | COVENANT LIVING |
178
+ | 2 | RAINIER REHABILITATION | 28.6 mi | 85.0 | 5/5 | 3/5 | 20% | 0 | — | THE ENSIGN GROUP|
179
+ ```
180
+
181
+ And the **rule-based recommendation** (no API key needed) — abbreviated:
182
+
183
+ ```
184
+ ### #1. COVENANT SHORES HEALTH CENTER
185
+ 3.0 mi away | DearNana score: 86.1/100 | CMS: 5/5 stars
186
+
187
+ **Strong on:** CMS overall rating (100/100), staffing levels (100/100), proximity (94/100).
188
+
189
+ Care measures relevant to the described needs (lower is better):
190
+ - long-stay antipsychotic use: 10.3% (state median 14.0%) — better than 75% of facilities in the state
191
+
192
+ **Ask on your tour:**
193
+ - What does a typical day look like for a resident with my loved one's needs, and who would I call with concerns?
194
+
195
+ **Best overall match: #1. COVENANT SHORES HEALTH CENTER** (86.1/100 — strongest on CMS overall rating, staffing levels)...
196
+ ```
197
+
198
+ (Facility data shown is from the CMS dataset at the time of the run and will change as CMS refreshes it.)
199
+
200
+ ---
201
+
202
+ ## Using DearNana Without AI Tokens
203
+
204
+ DearNana is fully useful with **no API key and no tokens**. Every step except the
205
+ final write-up — geocoding, fetching CMS data, scoring, ranking, and condition
206
+ matching — is plain Python that runs for free. When no `ANTHROPIC_API_KEY` is set
207
+ (or you pass `--no-ai`), DearNana produces a detailed **rule-based report**
208
+ instead of the AI one: per-facility strengths and weaknesses, automatically
209
+ surfaced red flags (abuse flags, CMS Special Focus status, actual-harm
210
+ inspection citations, penalties, ownership changes), condition-fit measures, and
211
+ concrete questions to ask on a tour — all derived from the same CMS data.
212
+
213
+ A fully token-free workflow:
214
+
215
+ ```bash
216
+ # Build the needs profile by answering guided questions (no AI), filter,
217
+ # export a CSV to share with family, and save the picks to a watchlist:
218
+ dearnana \
219
+ --address "Bellevue, WA 98008" --budget 8000 \
220
+ --interactive \
221
+ --min-stars 3 --exclude-abuse \
222
+ --export csv --save-watchlist
223
+
224
+ # Review your saved picks anytime:
225
+ dearnana --show-watchlist
226
+ ```
227
+
228
+ You also get a **side-by-side comparison table** of the top results in every
229
+ run, and the filter flags above narrow the pool before ranking. For a private
230
+ local AI write-up with no cloud tokens, see *Run Fully Local with Ollama* above.
231
+
232
+ ---
233
+
234
+ ## Library Usage
235
+
236
+ DearNana is also importable as a Python library. The FastAPI backend uses this pattern:
237
+
238
+ ```python
239
+ from dearnana import (
240
+ build_measure_weights,
241
+ compute_measure_benchmarks,
242
+ geocode_address,
243
+ parse_condition,
244
+ rank_facilities,
245
+ score_condition_match,
246
+ )
247
+ from dearnana.cms_client import fetch_facilities_by_state, fetch_mds_measures_by_state
248
+
249
+ lat, lng, state = geocode_address("Bellevue, WA 98008")
250
+ facilities = fetch_facilities_by_state(state)
251
+
252
+ # Optional: personalize the ranking with a needs profile
253
+ profile = parse_condition("moderate dementia, has fallen twice")
254
+ weights = build_measure_weights(profile)
255
+ mds = fetch_mds_measures_by_state(state)
256
+ benchmarks = compute_measure_benchmarks(mds)
257
+ condition_scores = {
258
+ ccn: score_condition_match(m, weights, benchmarks) for ccn, m in mds.items()
259
+ }
260
+
261
+ ranked = rank_facilities(
262
+ facilities, lat, lng, radius_miles=25, top_n=5,
263
+ condition_scores=condition_scores,
264
+ )
265
+
266
+ for r in ranked:
267
+ print(f"{r.facility.name}: {r.composite_score}/100")
268
+ ```
269
+
270
+ All public-facing functions are importable directly from the `dearnana` package. No subprocess calls are required.
271
+
272
+ ---
273
+
274
+ ## How Scores Are Calculated
275
+
276
+ DearNana uses a weighted composite score (0–100) based entirely on public CMS data. Here's what goes into it:
277
+
278
+ | Component | Weight | What it measures |
279
+ |-----------|--------|-----------------|
280
+ | Overall CMS Rating | 25% | CMS's own 1–5 star summary rating based on inspections, staffing, and quality measures |
281
+ | Health Inspection | 20% | Results of state health inspections — citations for care problems, medication errors, and safety issues |
282
+ | Staffing Quality | 20% | Blend of the CMS staffing star rating and actual nurse hours per resident per day vs. the 4.1 hrs/day minimum recommended by the 2001 CMS-commissioned staffing study |
283
+ | Staff Stability | 10% | Annual nursing staff turnover rate — high turnover often signals poor management and care continuity |
284
+ | Penalty History | 10% | Number of enforcement actions and total fines levied by CMS |
285
+ | Distance | 10% | Proximity to the address you searched — closer facilities score higher |
286
+ | Fire Safety | 5% | Whether the facility has full sprinkler coverage |
287
+
288
+ **Condition match (15%, when care needs are recognized):** Your `--condition` text is parsed into a needs profile (via a small AI call, or a built-in keyword matcher when no API key is set or `--no-ai` is used). Each need maps to CMS MDS clinical quality measures — e.g. dementia → long-stay antipsychotic medication rate and physical restraint use; fall risk → falls with major injury. Each facility's measures are scored against the **state percentile distribution** (lower is better for all tracked measures). When the condition component is active, the base weights above are scaled by 0.85 so all weights still sum to 100%. If no needs are recognized in the text, the ranking is identical to the base weights.
289
+
290
+ **Abuse flag:** If a facility has an active CMS abuse flag, 50 points are deducted from its score — this is treated as a near-disqualifying finding. When the needs profile includes a vulnerable population (dementia or mental health), the deduction increases to 60 points.
291
+
292
+ **Missing data:** Facilities with missing data for a component receive a neutral score (50) for that component. Facilities not yet rated by CMS (typically newer facilities) are included with neutral component scores and labeled "not yet rated".
293
+
294
+ **Ownership transparency (not scored):** Each facility's chain affiliation and the chain's average CMS ratings are shown alongside results. Warnings are flagged — not folded into the score, since chain averages aggregate the same star ratings already weighted above — when a facility belongs to a chain averaging ≤ 2.5 stars, changed ownership in the last 12 months, or carries CMS Special Focus status. For top picks, individual owners (name, role, percentage) from the CMS Ownership dataset are included in the report.
295
+
296
+ ### Scoring details
297
+
298
+ - **Overall CMS Rating** maps the 1–5 star summary directly to 0–100 (5 stars = 100, 1 star = 20).
299
+ - **Staffing Quality** is a weighted blend: 60% from the CMS staffing star rating, 40% from actual nurse hours compared to 4.1 hrs/resident/day — the minimum recommended by the 2001 CMS-commissioned staffing study (the actual national average is lower, ~3.6 hrs). If only one part is reported, it is used alone.
300
+ - **Staff Stability** inverts the turnover rate against national reference points (~52% total nursing, ~50% RN — CMS staffing-data analyses report national means of roughly 53% and 52%). A facility at the reference point scores 50; a facility with 0% turnover scores 100.
301
+ - **Penalty History** starts at 100 and deducts 15 points per enforcement action, plus 5 points per $10,000 in total fines.
302
+ - **Distance** uses linear decay: 100 at 0 miles, 0 at the search radius boundary.
303
+ - **Fire Safety** gives 100 for full sprinkler coverage, 50 for partial, 0 for none, 50 if unreported.
304
+ - **Condition Match** scores each relevant MDS measure as `100 × (1 − state percentile)` and averages them by need weight. Measures with missing data, or with fewer than 20 reporting facilities in the state, score a neutral 50.
305
+
306
+ ---
307
+
308
+ ## Data Source
309
+
310
+ | Attribute | Detail |
311
+ |-----------|--------|
312
+ | Source | [CMS Provider Data Catalog](https://data.cms.gov/provider-data/topics/nursing-homes) |
313
+ | Datasets | Provider information (ratings, staffing, chain), MDS Quality Measures (clinical measures), Health Deficiencies, Penalties, Ownership |
314
+ | Updated | Monthly by CMS (per dataset metadata) |
315
+ | Coverage | All Medicare/Medicaid certified nursing homes in the US (~14,700 facilities as of mid-2026) |
316
+ | Cost data | State-level monthly medians for semi-private rooms from the [CareScout (Genworth) Cost of Care Survey 2024](https://www.carescout.com/cost-of-care) — **not** facility-specific pricing |
317
+ | Caching | API responses are cached for 24h under `~/.dearnana/cache` |
318
+
319
+ CMS does not publish per-facility pricing. Budget comparisons use state-level median costs as a rough proxy. Contact facilities directly for current rates. Many facilities accept Medicaid — contact them directly if your budget is below the state median.
320
+
321
+ ---
322
+
323
+ ## Disclaimer
324
+
325
+ DearNana is a decision-support tool, not a substitute for professional medical or legal advice. Always visit facilities in person, speak with staff, and consult with a healthcare professional before making placement decisions. See [DISCLAIMER.md](DISCLAIMER.md) for full details.
326
+
327
+ ---
328
+
329
+ ## Contributing
330
+
331
+ Issues and PRs are welcome. Before contributing changes to scoring weights or methodology, please read [DISCLAIMER.md](DISCLAIMER.md) for notes on data accuracy and known limitations. Scoring changes should include a rationale and a before/after comparison on a representative set of facilities.
332
+
333
+ ---
334
+
335
+ ## License
336
+
337
+ MIT — see [LICENSE](LICENSE)