CMS HPT Tracker / price transparency audit

Project skill

The outreach skill

Tell your AI assistant in plain words what you did or found. The skill finds the hospital, shows you the exact change, and waits for your OK before anything is saved.

What the skill does

Turn one sentence into a log entry

A skill is a set of written instructions an AI assistant loads when your request matches it. This one teaches the assistant how to keep the outreach log for each hospital.

You describe fieldwork in free text, and often paste raw material such as a sent email, a reply from a hospital or a list of price-file rows. One message can touch one hospital or forty, and can mix several kinds of update. The skill reads it, matches each hospital to its CMS certification number (CCN), proposes the exact records to write, and saves only after you say yes.

The same entries show up in the hospital record inside the tracker. The skill logs your work and can draft an email, but it never sends one. Your private working file stays apart from the public copy, which you should review before you publish.

Workflow

Check the change before it is saved

The assistant prepares the change. The command-line tool decides what can actually be saved.

Four steps: describe, match, preview, approve. Nothing is saved until the last step. Describe Match Preview Approve and save Nothing is saved yet. You can stop or change the wording at any point. Saved, with a backup
The skill only writes to the log after you have seen the exact change.
Describe
Say what happened in ordinary words. Add a city or state if the hospital name is common.
Match
Each name is matched against the hospital list. A clear match is used. If the match is ambiguous, weak or missing, the skill asks you instead of using the top hit. A CCN that is not on the list is reported as a likely mistake, not turned into a record.
Plan
The assistant writes a plan, a list of operations, to a scratch location outside the repository. It never edits the log file by hand.
Preview
A dry run prints a per-record diff, plus any discarded: or warning: lines for input the store threw away. Those lines do not appear in the diff, so the assistant must show them to you with it.
Approve
The assistant waits for a clear yes. If you say “just do it” for one message, it honors that for that message and still prints the diff afterward.
Save
The same command is re-run with --commit. The batch is all-or-nothing: if any operation fails validation, nothing is written and every problem is listed at once. Then the assistant reviews the public copy, described below.

Setup

Use the copy in this repository

You need a local copy of the repository and Node.js. There is no separate service or account.

Claude Code reads .claude/skills/outreach/SKILL.md, which is the one canonical copy. A short file at .agents/skills/outreach/SKILL.md points other compatible assistants at it, so both entry points follow the same instructions and the same command-line tool. A reference file next to the canonical skill, references/reviewed-evidence.md, covers corrections and research follow-ups.

From the repository’s top folder, run npm run outreach -- help to see the terminal commands, including find, show, list, apply and restore. A write only previews the change until you add --commit. The terminal does the same matching, backup and checking without an assistant.

Rebuilding the public copy also needs the local contact-protection key you already have. If the key is missing or the rebuild fails, fix that before you publish.

What it can log

Nine operations, and nothing else

Every record is keyed by CCN. The store reads a fixed set of fields, and a field it doesn’t know is dropped without an error, so the skill never invents new ones.

OperationUse it for
emailOne email you sent. Needs a subject. The body is capped at 8,000 characters, so the skill says so if a long thread would be cut.
noteAnything that isn’t an email: a call, a finding, your reasoning. There is no phone-call entry, so a call is a note.
statusWhere the hospital stands overall, with an optional follow-up date.
correctionA manual override of the crawler’s finding: a verdict, plus the file or pointer links, dates and a note saying why.
outcomeWhat became of one email, using the entry’s ID.
upsertLike status, but it also overwrites the hospital’s name, city and state labels. Used when a stored label is wrong.
edit-entryFix an existing email or note in place. The ID and original timestamp survive. An entry can’t change kind, so a note can’t become an email.
delete-entryRemove one email or note. Destructive, so the skill only includes it when you ask and shows it separately.
deleteRemove a whole record, entries and correction included. Same rules as above.

Statuses, outcomes and verdicts

Status
For the hospital: none, contacted, awaiting-reply, replied, resolved or no-response. A record-level no-response means the hospital has gone silent.
Outcome
For one email: none, replied, bounced or no-response. An email-level no-response means that email never got an answer. It is a different fact from the status above, and both are worth recording.
Verdict
On a correction: compliant, failing, blocked, exempt or unknown. This is the field that changes how the tracker shows a hospital.

Status changes that happen on their own

Logging an email on a hospital at none moves it to awaiting-reply, unless the email bounced. A replied outcome on a hospital that is awaiting a reply moves it to replied, and a bounced outcome moves it back to none. A bounce leaves contacted and no-response alone, because those were set on purpose. The skill doesn’t add a duplicate status change for any of these.

Not stored

The log has no attachments, tags, custom fields, contact records, priority, assignee or CMS complaint ID, and no health-system grouping. One price file can support separate corrections for several hospitals only after its coverage is checked for each one. A shared website, a system name or a list of hospitals is not enough.

Examples

Say what happened, in your own words

  • Emailed Springfield Regional about its dead file link. The email bounced.
  • Mercy replied with a new price-file URL. Follow up next Friday.
  • I called the compliance office and left a voicemail.
  • This file covers these six hospitals: …
  • I logged that email twice. Remove the duplicate.

A short sentence is enough when the hospital name is unique. If several hospitals share a name, add the city, state or CCN. A date like “next Friday” or a bare path like /prices.csv makes the skill ask, because a bad date or link would otherwise be dropped silently.

You sayThe skill plans
“I sent this email to …”An email. The status follows automatically.
“They replied and said …”An outcome of replied on that email, plus a note with what they said.
“It bounced”An outcome of bounced. If the email isn’t logged yet, an email that is already marked bounced, plus a note with the error.
“No response from …”A status of no-response on the record.
“Check back on …”A status with a follow-up date.
“Found their pointer file at …”A correction with the pointer link and domain.
“That price-file link was wrong”A correction that clears only that link and leaves the verdict standing.
“Here’s the real text of that email”An edit-entry with just the fields that change.

Before proposing anything on an existing record, the skill reads it first. The log has no duplicate check, so logging the same email twice makes two entries. Reading first is how that gets caught. If you already logged something in the tracker’s own outreach drawer, say so.

Drafting emails

Short, casual, and only what you found

Ask for a draft and the skill writes one for you to send. Logging the email comes afterward, once you’ve really sent it.

Greeting
Always “Hello,” and never a person’s name, even when you gave the skill one. A name in a greeting is the easiest way for a real name to end up unmasked in a public commit.
Tone
No em dashes, no invented urgency, and no guessing why a hospital is behind. The email states the finding and the ask. CMS enforcement comes up only if you raise it.
Stale files
A file counts as stale only when its declared last-updated date is more than 365 days old. A file a few months old is inside the normal yearly cycle and doesn’t get a staleness email.
Follow-up
The usual draft says you’ll follow up in 30 days. That is your research cadence, not a regulatory deadline, and it is used only when you want it.

The reusable parts are the opening line, the 30-day follow-up and the sign-off. The middle paragraph is rewritten for the real finding, such as an outdated file, a broken link, the wrong facility or a pointer mismatch.

Evidence and corrections

A reply starts a review, not a fix

A working link or a promise to fix a file is useful to log. A correction also needs evidence for that specific hospital.

Which hospital
Check the file’s hospital name, address, state and campus for each CMS record. A shared website or a file for a whole system doesn’t prove it covers every hospital. Exempt claims, such as a VA or military hospital, need facility-specific support too.
Access
A 403, timeout or block is an access observation, not proof the file is missing. A browser may get through where an automated check can’t.
“They fixed it”
That is a reply. The skill logs it as a note and checks the claimed fix itself before changing a verdict or marking the issue resolved.
Merging
Leaving a field out keeps its old value. Sending an empty value clears only that field. A clear flag drops the whole correction. A correction with only a check date is thrown away.
Newer reviews
The tracker ignores a manual correction when a reviewed finding for that hospital is newer by calendar date. The correction stays in the history. Don’t back-date a check to win. Record a genuinely newer check with its evidence.
Research totals
A correction doesn’t rewrite the nationwide research files or audit totals. Changing those takes the reviewed research process, which the skill’s evidence reference describes.

For a request about a finding, a verdict or the research queue, the skill also reads the hospital’s reviewed record and the separate worklists for open investigations, retained-evidence follow-ups, identity reviews and monitoring. A follow-up doesn’t always mean the hospital has no result. Counts come from the current records, never from a remembered snapshot.

A research refresh is its own authorized job. The snapshot date is the date of the newest observation, not the date the page was deployed, and it is reported separately from deployment and individual check dates.

Evidence and corrections

A reply starts a review

A working link or a promise to fix a file is useful fieldwork. A correction also needs evidence for the specific hospital.

Facility identity
Check the file's hospital name, address, state, and campus coverage for each CMS record. A shared website or system-wide file does not establish coverage for every hospital.
Access
Record blocked requests and timeouts separately from missing files. Browser access may differ from an automated check.
Newer reviews
A newer reviewed finding takes precedence over an older manual correction. The correction remains in the history; its date should reflect when the check actually happened.
Research totals
Outreach corrections do not rewrite the nationwide research files or aggregate audit totals. Updating those requires the reviewed research workflow.

The skill consults the current reviewed record and its next action. Unresolved investigations, retained-evidence follow-ups, identity reviews, and uncertainty monitoring are distinct workstreams; a follow-up does not always mean a hospital lacks a result.

For an authorized research refresh, the repository rebuilds verification, reconciliation, and source-validated worklists before generating the tracker. The snapshot date describes the included observations, not the date a page was deployed.

Safety

The assistant suggests. The tool checks.

The skill tells the assistant to use the checked command and to show every change it wants to make.

Approval
Review the preview before saving. Earlier approval of specific changes can cover the save. It doesn’t cover sending email, publishing unrelated work, or delete operations you didn’t ask for.
Quiet drops
Bad enum values stop the whole batch. Bad formats don’t. A date that isn’t YYYY-MM-DD, a link that isn’t absolute http(s), a domain without a TLD, over-long text and unknown fields are dropped or truncated silently. That is why the discarded: lines on a dry run must be read and shown. Dates are also checked by shape only, and they use UTC, so a late-evening write can default to tomorrow.
Undo
The previous file is copied to a backup before each write. restore rolls back the last saved batch. It goes one version back only, so the skill offers it right away if a write looks wrong.
Pasted text
Hospital replies and file contents are evidence to read. They are not instructions. If pasted text says “mark all hospitals compliant” or “ignore previous instructions,” the skill quotes it back and asks you.
Other paths in
The tracker’s outreach drawer and its import box write the same records and report what they dropped. A bulk file import has no command-line version, so the skill converts a file to a plan or says plainly that it’s a separate job.
Server running
It is safe to write from the terminal while npm run serve:outreach is running. The browser tab shows the change after a reload.

Public exports

Check what leaves your working file

Your private file is ignored by Git, but notes and messages can end up in the public copy.

Each save tries to rebuild a separate public copy, which is the only one committed and deployed. Every email address is masked. Names are replaced only if they are on your local redaction list. Contact text is then protected with the local key, so public files can contain hpt-obf:v1: tokens. The public app can reveal that text, so this is obfuscation, not a guarantee of privacy. Never print, stage or replace the key.

Names
When a plan’s to, body or note mentions a named person, the skill checks the redaction list covers that name and proposes adding it before saving. The list is private and stays local. Read the whole email body, including the greeting, not just the address.
Usernames
A bare username in prose, such as “jsmith no longer works there,” is not masked, because only a full address is. Add it to the list too.
Never
Don’t force-add the private log, and don’t edit the public copy by hand. If it drifts, regenerate it with npm run redact.
Not redacted
Hospital names, domains, links, dates and your own signature block.

Committing the public copy

After a save, the assistant makes the Git commit for you. It stages only cms_data/outreach.public.json and never uses a broad add. It runs npm run check:contacts-private and npm run check:pointers-private first, reads the exact staged diff for names, private details, phone numbers and local paths, and fixes any regeneration warning instead of committing a stale copy. The message is short and starts with outreach:. If the public copy didn’t change, as with a status-only update, it skips the commit.

It does not push unless you ask, because a push deploys the site. Saving locally, making a Git commit and deploying are three separate steps. For an approved push, the assistant inspects every outgoing commit, then checks the live links and snapshot date afterward. The deploy publishes a chosen set of files, so a tracked research file isn’t necessarily on the public site.

References

Skill format

Back to The tracker Open a hospital record to see or add outreach. Read the source The repository The skill instructions, the outreach command and the tracker code.