AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Medical Records

skill-pfeff-claude-skills-medical-records · by pfeff

File a medical After Visit Summary into the Obsidian vault as a structured, queryable record. Extracts vitals and visit metadata from the document text, writes a dated note with flat Number frontmatter properties (so Obsidian Bases and Dataview can trend vitals across visits), archives and embeds the source scan, and slots the note into the Medical Vitals base. Usually invoked by the scan-documen…

No reviews yet
0 installs
24 views
0.0% view→install

Install

$ agentstack add skill-pfeff-claude-skills-medical-records

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-pfeff-claude-skills-medical-records)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Medical Records? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

medical-records — file an After Visit Summary

A handler skill: turns the text of a medical After Visit Summary into a structured vault record. Consumes OCR'd text (from scan-document, or produced here if invoked directly) and the source file; produces a dated note + archived scan.

When this fires

  • Invoked by scan-document for class medical.after-visit-summary.
  • Direct: "file this doctor visit", "capture this after-visit summary", "log my visit vitals".

Trigger signals (how scan-document recognizes this)

This handler owns its own recognition vocabulary — scan-document's router does not hardcode these; it reads this section to decide whether a scan belongs here. A document is an After Visit Summary when the recognized text shows several of:

  • Header/title text: "After Visit Summary"
  • An MRN (medical record number)
  • Vitals (blood pressure, weight, pulse, temperature, BMI, oxygen saturation, etc.)
  • A provider/clinic/institution name
  • A follow-up date or discharge instructions

One signal alone may be coincidental (e.g. a phone number that looks like an MRN); several together are a confident match. Ambiguous cases should be confirmed with the user rather than guessed.

Inputs

  • Path to the source scan (PDF/image).
  • The recognized text. If not supplied (direct invocation), OCR it first: pdftotext -layout "" - fast path (only if the pdftotext binary is present — it is not part of stock macOS; treat "command not found" as "skip to Vision," not an error), else swift /scripts/ocr.swift "".

Command safety: the file path is untrusted input (user- or filesystem-derived). Always pass it as a single quoted argument to any shell command — never interpolate it unquoted — and reject/validate it if it contains shell metacharacters (; | & $ \ ( ) newline`) before invocation.

Steps

  1. Extract these fields from the text (leave a field out if genuinely absent — do not invent):
  • Visit metadata: visit_date (the appointment date), provider/institution, department, department phone, MRN, reason(s) for visit, referral(s) + expiry, follow-up date, medications.
  • Vitals: blood pressure (systolic + diastolic separately), weight, BMI, height, pulse, temperature, oxygen saturation.
  1. Resolve the vault via the obsidian-notes host-config (~/.claude/hosts/.md). Bail clearly if none is configured.
  1. Path safety: slug and visit_date are both derived from OCR'd text and are therefore untrusted — sanitize both before using them to build any Attachments/ or Notes/ path. Constrain slug to [a-z0-9-] (lowercase, strip/replace anything else, collapse repeats). Validate visit_date as strict ISO YYYY-MM-DD; if it doesn't match, treat it as unrecoverable and fall through to the "ambiguous visit date" edge case rather than using the raw value in a path. Never write an unvalidated slug or visit_date into a filesystem path — this blocks path traversal (../, absolute paths, embedded separators) riding in through OCR text.
  1. Archive the scan: copy the source file into /Attachments/ named -. (e.g. 2026-06-03-osu-sleep-avs.pdf), using the sanitized values from step 3. The attachment is a source artifact — name it by the document's own date for findability. Verify the filename is unique in the vault (the embed resolves by filename).
  1. YAML safety: title, provider, department, department_phone, each visit_reason item, referral, and medications are all derived from OCR'd text and are therefore untrusted — never write any of them into frontmatter unquoted. Emit every OCR-derived scalar as a double-quoted YAML string with internal " escaped as \" and \ escaped as \\ (or as a YAML block scalar for long/multi-line values). A stray :, a leading -, an embedded newline, or a line that merely resembles --- or key: value in the source text can otherwise break the YAML frontmatter block or inject extra properties — and medical text is full of colons (times, ratios, dosages). This applies to every scalar in the schema below sourced from OCR text, not just the ones named here.
  1. Write the note at /Notes///-.md (sanitized slug):
  • Filename prefix = today's write date, NOT the visit date. The prefix is a de-dupe / folder-partition key; the visit date lives in frontmatter as visit_date.
  • Frontmatter — the schema (see below). Vitals are flat, top-level, Number-typed properties. This is deliberate and load-bearing (see "Why this schema").
  • Body: visit header, a human-readable vitals table, plan & follow-up, a condensed instructions summary (keep patient-specific guidance; the full text lives in the embedded PDF), and the embedded source (![[]]).
  1. Report where the note and attachment landed, and note that it will appear in the Medical Vitals base.

Frontmatter schema

Every OCR-derived scalar below (title, provider, department, department_phone, visit_reason items, referral, medications) MUST be written as a quoted, YAML-safe string — see "YAML safety" in Steps above. Do not write raw OCR text into frontmatter.

---
title:  — After Visit Summary
type: medical-visit
visit_date: 2026-06-03            # semantic date (Date type)
tags:
  - medical/visit
  -                    # e.g. sleep-medicine
provider: 
department: 
department_phone: 
mrn: ""                      # quoted — keep as Text, not a number
visit_reason:
  - 
referral:      # omit if none
follow_up: 2026-12-03             # omit if none
medications: 
source_pdf: "[[]]"
captured: 2026-07-13              # write date; matches filename prefix
# --- vitals: flat Number properties → Bases columns / Dataview trending ---
bp_systolic: 122
bp_diastolic: 68
weight_lb: 188
bmi: 26.98
height_in: 70
pulse_bpm: 77
temp_f: 97.3
spo2_pct: 99
---

Why this schema (do not "improve" it back to the obvious-but-wrong forms)

Verified against Obsidian's official Properties and Bases docs:

  • Vitals are flat top-level properties, not a nested vitals: object. Obsidian's Bases model is literally "each row is a file, each column is a property of that file," and Bases/Dataview read frontmatter only, never the note body. Nested properties are not supported in the Properties UI. So flat frontmatter is the correct — and only — form that serves both Bases and Dataview.
  • Blood pressure is split into two Numbers (bp_systolic/bp_diastolic), not a single 122/68 string. Obsidian has 6 property types (Text, List, Number, Checkbox, Date, Date&time) and no unit type; a 122/68 value is Text and can't be trended. Split → both Numbers → aggregatable.
  • Numbers are bare (no quotes, no units in the value) so they type as Number. Units go in the key (weight_lb, temp_f) since there is no unit type. mrn is the exception — quote it so it stays Text.
  • No vital_ prefix. type: medical-visit already scopes these; clean names make better Base columns.

The Medical Vitals base

Records feed /Areas/Health/Medical Vitals.base — a table filtered to type == "medical-visit", sorted by visit_date, with the vitals as columns and a bp formula (bp_systolic + "/" + bp_diastolic) for display. It exists after the first record; adding visits just adds rows. If it is missing, recreate it with that shape.

Edge cases

  • Missing vitals: omit absent properties rather than writing nulls or zeros — a zero would corrupt trend averages.
  • Ambiguous visit date: if the appointment date isn't clearly recoverable, ask (AskUserQuestion) rather than guessing; it is the semantic key.
  • Non-AVS medical doc (lab result, imaging, immunization): out of scope for v1 — say so and fall back to the router's generic capture. Those get their own handlers later.
  • Height unchanged across visits: fine to carry it each time; it makes each record self-contained.
  • Sensitive content: these records carry MRN and vitals — private medical data by nature. Capture into the local vault only; never send content (including the file, extracted text, or any field) to an external service without explicit operator say-so.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.