SkillAgentSearch skills...

roadmap

Health by Dr Brad: a free, local-first personal health record and preventive health plan. Your data stays in one JSON file in your own cloud. Hosted MCP server for Claude and ChatGPT, plus an offline CLI.

Install / Use

claude mcp add DrBradStanfield -- npx -y github:DrBradStanfield/roadmap

If the server publishes to npm under a different name, use that package instead — check the repo README.

About this skill
🔌

MCP Server

Model Context Protocol server

Quality Score

83/100

Supported Platforms

Claude Code
Claude Desktop

Tags

Our assessment of roadmap

roadmap scores 83/100 on our quality scale, 649th of 946 AI & Machine Learning skills we index.

Its MCP Server is 15 KB long, well organised into 8 sections with 2 code examples: a thorough specification that gives an agent plenty to work with.

It has 10 GitHub stars, so there is little community track record yet; judge it on its content.

Substance
30/30
Structure
18/20
Description
15/15
Adoption
4/20
Freshness
15/15

Maintenance, license and trust

  • The repository was last updated today, so roadmap is actively maintained.
  • It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
  • Its trust signals score 97/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.

roadmap compared with similar skills

All 4 of these similar skills score higher than roadmap; compare them before choosing.

SkillScoreStarsUpdatedFormat
roadmap (this skill)by DrBradStanfield8310todayMCP Server
claude-memby thedotmack100102.1k1d agoCLAUDE.md
Agent-Reachby Panniantong100100.6k1d agoCLAUDE.md
Understand-Anythingby Egonex-AI10087.5ktodayCLAUDE.md
headroomby headroomlabs-ai10077.2ktodayCLAUDE.md

Frequently asked questions

How do I install roadmap?
Run claude mcp add DrBradStanfield -- npx -y github:DrBradStanfield/roadmap. The install tabs above show the steps for each supported agent.
Which AI agents does roadmap work with?
It is written for Claude Code and Claude Desktop, as a MCP Server file. Other agents that read the same format can often use it too.
Is roadmap safe to use?
It is MIT-licensed and scores 97/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is roadmap still maintained?
The repository was last updated today, so roadmap is actively maintained.

Health by Dr Brad

A free health roadmap. Enter your measurements and blood test results, and it shows which screening tests are due, with evidence-based suggestions and their citations. Use it at https://drstanfield.com/pages/roadmap, no account needed. Connect it to Claude or ChatGPT with the connector URL https://mcp.drstanfield.com/mcp. Your record is one file, health-roadmap.json, in your own Dropbox or Google Drive or your browser; our server never keeps it.

Health-metric tracking with personalized suggestions, delivered as a Shopify storefront theme extension and as a self-hosted page.

Local-first. A user's health data lives in their own cloud (Google Drive, Dropbox, GitHub, WebDAV) or in localStorage, as a single health-roadmap.json file. The website and the local tools never send that file to our server; the hosted connector at mcp.drstanfield.com holds it in server memory for the length of one request and stores none of it. "Logged in" means a cloud provider is connected. The Fly backend is thin: chatbot, lab-import extraction, A/B and product events, email reminders, Klaviyo capture, and the hosted MCP server. Supabase holds operational rows only, never health values. Email reminders are the one place a screening name reaches us: that row holds the enrolled email address, the screening labels and the dates they are due, and nothing else (app/lib/reminder-v2.server.ts).

The three agent surfaces

The same file, the same write path, three ways in.

  1. Widget: the React app in the storefront or on the self-hosted page. Reads and writes through RoadmapStore.
  2. CLI and stdio MCP: tools/get-plan.ts, tools/edit-record.ts and tools/mcp-server.ts, running on the user's own machine against their own file. See docs/guides/getting-started.md ("An open-source health record you can connect to any AI", the hub guide), docs/guides/command-line.md and docs/guides/connect-claude-desktop.md.
  3. Hosted MCP: https://mcp.drstanfield.com/mcp, live since 2026-09-02 on the Fly app health-tool-edu, over Dropbox and Google Drive. Nine tools as of 2026-09-07: the hosted-only import_documents (US-35) reads lab files from the Dropbox app folder (Drive's drive.file scope cannot see dropped files), and file_results (US-36) takes the rows the assistant read from a file dropped into the chat, so the file never reaches our server. On Dropbox a read also names folder files not yet in the record (US-37).

To answer one hosted call, the server unseals the cloud credential the assistant holds, opens the user's folder with it, and holds the record in server memory for the length of that request. It stores none of it. (One exception, for an invented account: while an OpenAI or Anthropic app review is pending, the server holds the reviewer account's Dropbox credential itself; US-32 AC38.) Anyone who does not want that runs surface 2 instead: tools/mcp-server.ts is the same tool layer over the same file with no server of ours in it at all (docs/guides/getting-started.md, the hub guide, and docs/guides/connect-claude-desktop.md).

Every non-browser writer goes through the same SyncManager (packages/health-core/src/sync-manager.ts), which merges on conflict and verifies after writing. The CLI and stdio MCP run it over file-adapter.ts, which takes a lock file and keeps backups. The hosted MCP runs it over the REST adapters (dropbox-rest.ts, drive-rest.ts), where the provider's own conditional write does the same job. See packages/health-core/README.md.

Rows are never mutated. A correction appends a new row and marks the old one entered-in-error.

Two builds, one source

| Build | Command | Where | | --- | --- | --- | | Shopify storefront | npm run build:shopify-prod | both stores, theme extension | | Self-host | npm run build:pages | GitHub Pages, almost no backend, bring your own keys |

Flags: VITE_LOCAL_FIRST for all v2 behavior, VITE_SHOPIFY_SURFACE to gate the features that need our server.

"Almost no backend" is the honest version of the Pages build. The record and the chat never touch our server there: the record is written straight to the user's own cloud, and chat runs on the user's own key. Two optional calls do reach us, and only if the user makes them. Signing in with Google posts the OAuth code to /api/google-token, which forwards it to Google and stores nothing (widget-src/standalone/google-config.ts). Enrolling in email reminders posts the address and the due dates to /api/reminders-v2 (widget-src/standalone/reminders.ts). Sentry error reporting also runs on this build (widget-src/standalone/app.tsx calls initSentry), scrubbed by widget-src/src/lib/sentry.ts before anything leaves the browser: on drbradstanfield.github.io it is enabled, under the environment name standalone, so the page does talk to sentry.io. The scrub is the same one the storefront build runs, the shared scrubEventText over every free-text field of an event, so a Pages error is reported under the same rules as any other.

The rest of what the page loads is its own. widget-src/standalone/index.html carries one module script and loads no third-party script at load time; Sentry is bundled into it, and the hero image ships with the build (widget-src/standalone/hero-dr-brad.webp, 26 KB) rather than being fetched from cdn.shopify.com, so loading the page tells Shopify nothing. Connecting Google Drive loads Google's sign-in script from accounts.google.com. Cloud credentials and the optional Anthropic key live in localStorage for that origin (hr_anthropic_key, health_roadmap_dropbox_tokens, health_roadmap_gdrive and health_roadmap_gdrive_tokens, health_roadmap_github, and health_roadmap_selfhost, which holds a WebDAV username and password), where any script running on the origin can read them. /roadmap/ and /roadmap/dev/ are the same origin, so the staging preview shares that storage with the live page.

Getting started

git clone <repo-url>
cd roadmap
npm install
cp .env.example .env   # fill in what you need
npm run test:all

Node 22 or newer. Never run shopify app dev: the dev preview overrides production.

Tests

npm test          # symlink guard + health-core + server
npm run test:all  # everything, and what CI runs
npx vitest run <path>

Deploy

CI is the deploy path: .github/workflows/deploy.yml, triggered from Actions → Deploy → Run workflow. All credentials live in the GitHub production environment. Manual and emergency steps, plus the two-app Fly split, are in docs/deploy-runbook.md.

Verifying this yourself

You do not have to take the code's word for it. Open the site with the DevTools network tab recording and use the widget.

  • Saving a metric produces no request to our server. The record file is written only by the adapters in widget-src/src/storage/ (dropbox.ts, drive.ts, github.ts, webdav.ts, local-storage-adapter.ts), so the write goes to your own Dropbox, Google Drive, GitHub, WebDAV server, or localStorage. No endpoint on our server accepts the record for storage. The hosted connector is the one place a record reaches our server at all, and only if you connect one: it reads the file in server memory for the length of one request and stores none of it.
  • Two requests carry health content, and you trigger both. A lab-document upload POSTs the document's page content to /api/lab-import-v2, which sends it to Anthropic's API for extraction, returns the values, and stores none of them. Sending a chat message from the storefront widget POSTs the message, that conversation's earlier turns, and the health context needed to answer it to /api/chat. On that surface the server stores one row per question: the first 500 characters of the text you typed, nothing more, which may hold health details you wrote into it; the articles it matched; its classification; the router's raw output and any router error; the name of the surface; and a pseudonymous session and conversation id. The earlier turns and the reply are not stored. A daily job blanks the question text, the router's raw output and the error text once a row is 30 days old; the match record stays: the articles, the classification, the ids. A guest session row holds a hashed address, not an IP.
  • The chat bubble on blog pages and the chatbot embed send less than the widget's chat, and keep more. Both read the widget's copy of your saved record out of localStorage and send it as chat context on every message (loadGuestInputs() in widget-src/src/lib/storage.ts, called from widget-src/src/site-chat.tsx and widget-src/src/chatbot-embed.tsx). That context is your saved profile (sex, height, birth year and month, unit system); the latest saved value of each measurement, with its date; the medications on record, with drug names and doses; and every screening answer on record: methods, results, dates and follow-ups, your smoking history and pack-years, your PSA value, your answers on discussing prostate and endometrial screening, and your answer about abnormal bleeding. Nothing you typed without saving is in it. The widget's own chat sends all of that, plus up to 24 dated values per measurement and whatever is typed on the page but not yet saved. Neither bundle sets VITE_LOCAL_FIRST, so the server takes them for a stored surface: it writes your question and the reply into chat_messages, and the reply can quote the values you were sent with. Those cached values are still sent as context; Brad chose on 2026-09-10 to keep that, because the answer is worse without them. The transcripts now join the same 30-day purge (app/lib/chat-purge-cron.server.ts): once a row is 30 days old the job blanks the message text and the conversation title, which is the first words of your question. What stays is the shape of the thread, not the words: row ids, the role, the timestamps, the model, the token counts, and the fallback flags. A blanked turn reads back as [removed after 30 days]. The Discord bot's transcripts are blanked on the same clock, decided 2026-09-10: a question typed at the bot is as private as one typed into the bubble. The YouTube transcripts stay, because those turns are public comments on a video under their own retention.
  • Two devices editing apart converge without a conversation. If both record the same measurement for the same day while apart, the newer entry becomes that day's value; the other stays in your history marked entered-in-error. Nothing is deleted. The record file is the trust root: anything that can write it can already delete it outright, and a file carrying a later erase wins on every device. Recovery is your provider's version history.
  • Telemetry is a closed allow-list of event names in packages/health-core/src/product-events.ts. An event is a name plus an anonymous visitor UUID, and the server rejects any name off the list.
  • Nothing else we call carries a value. /api/google-token forwards an OAuth code or refresh token to Google and stores nothing. /api/reminders-v2 sends your reminder schedule, which is a label such as "Colonoscopy" and a due date. On the storefront you do not have to enrol: connecting a cloud provider enrols you, because that connection IS the consent (autoEnrolReminders in widget-src/standalone/reminders.ts, the default-on decision of 2026-08-11). Your cloud account's email address, the labels and the dates reach us on that conne

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars10
CategoryAI
Updated4h ago
Forks3

Languages

TypeScript

Trust signals

97/100

From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.

1 info