← back to the lab

medscript

medication handoff notation

a tiny handwritable symbol set for medication lists at handoffs — think "markdown for med lists." it makes the communication layer legible, compressible, and portable across paper, charts, and SMS. the next clinician must decide fast what's active, what changed, what's uncertain, and what's dangerous. today's notes hide all four inside competent-looking prose. medscript puts each one in the left margin, in a symbol, where the eye lands first.

frozen v1: 10 symbols, 2 modes, 1 ascii fallback, hard scope walls. a stranger can implement a parser/validator from the parser contract below without asking questions — that was the acceptance test, and the document is written to it. this page is the full spec, hosted at home so it can't die with somebody else's platform.

disclaimer — desk work only

this specification is desk work only. it has not been clinically validated. none of the authors are clinicians. this is a complete, rigorous, internally consistent design document — not a clinical guideline, not a medical device, not an endorsement for use in patient care. real-world validation requires real nurses, pharmacists, and physicians in supervised pilots. do not deploy this in clinical practice on the strength of this document alone.

the problem

competent prose, hidden gaps

at every handoff, the next clinician must decide fast: what's active, what changed, what's uncertain, what's dangerous. today's notes bury all four inside competent-looking prose. the prose looks complete, so nobody asks the question it silently didn't answer. that's where the harm lives.

medicine already standardizes terminology, coding, and structured orders. it does not standardize the scribble on the handoff sheet — the layer where meaning is actually lost. medscript is that layer. it is not a replacement for clinical judgment, an ordering system, or a terminology code. it sits under all of those.

the design analogy: sheet music. the notation must preserve meaning under pressure, stay readable across contexts, and feel intuitive enough that basic information decodes without a codebook.

design principles (non-negotiable):

§3 · the frozen set

ten symbols. that's the whole set.

the symbol leads the line — scan the left margin, know the story before reading a word. click any symbol to copy it.

reviewed1 / 10

reviewed, no change. the entry was verified against a source and stands as written.

= lisinopril 10mg PO ×1

click the symbol to copy

added2 / 10

newly added at this transition point.

+ apixaban 5mg PO ×2

click the symbol to copy

inactive3 / 10

discontinued or held — inactive either way. the bracket MUST say which (rule V4). preferred over - (ambiguous vs hyphen) and — (typographic).

∅ atorvastatin 40mg PO ×1 [pre-op hold — resume POD2]

click the symbol to copy

increased4 / 10

dose increased. the line MUST use old→new notation (rule V3).

↑ sertraline 50mg→100mg PO ×1 [titration — week 3]

click the symbol to copy

decreased5 / 10

dose decreased. the line MUST use old→new notation (rule V3).

↓ metoprolol succinate 50mg→25mg PO ×1 [tapering — cardiology]

click the symbol to copy

conditional6 / 10

conditional / PRN. the bracket MUST state the condition; ×N on a ~ line is the ceiling per 24h, not a schedule (rule V2).

~ oxycodone 5-10mg PO ×6 [pain ≥4/10 — max 6/24h]

click the symbol to copy

critical7 / 10

allergy, dangerous interaction, or care-blocker. demands attention before anything else on the page.

!! penicillin [anaphylaxis]

click the symbol to copy

uncertain8 / 10

something on this line is uncertain. the bracket MUST explain why — a bare ? is invalid (rule V1).

? aspirin 81mg PO ×1 [pt unsure if still taking]

click the symbol to copy

instruction9 / 10

administration instruction: timing, food, condition. attaches to its line only — never the next one (rule R7).

= levothyroxine 75mcg PO ×1 @fasting / 30min pre-food

click the symbol to copy

frequency10 / 10

N doses per calendar day. replaces qd/bid/tid/qid (already recognized as error-prone). non-daily schedules go in @ (rule V6).

×2 = twice daily · ×1 = daily · ×4 = four times daily

click the symbol to copy

frozen means frozen. no new symbols may be added to v1 documents. proposals for v2 must be flagged PROPOSED — not frozen and must not appear in v1-conformant documents.

rejected during design (do not reintroduce silently): ⚠ (hard to handwrite) · [ ] hold marks (confused with parentheses) · — for discontinuation (ambiguous vs hyphen) · Δ for discrepancy (too learning-dependent) · HLD (english-dependent) · qd/bid/tid (error-prone).

stress tests · the hard cases

five hard cases

each "before" is a competent-looking, professionally formatted note — the kind a good clinician writes today. the danger in every one is the same: it looks complete, so nobody asks the question it silently didn't answer. the "after" should feel like relief, not cleverness.

case 1 — PRN / conditional dosing (condition + ceiling)

the trap: PRN orders look precise ("5-10mg q4-6h PRN pain") while hiding three decisions: which dose, what threshold triggers it, and the daily ceiling. the nurse at 3 a.m. makes all three alone.

before
PRN MEDICATIONS (admission orders, 09/30)
  Oxycodone 5-10 mg PO q4-6h PRN pain
    — assess pain prior to administration; hold if RR < 12
    — may repeat per pain scale
after
[post-op floor, 09/30, 14:22, RN:SK]
ALLERGY:
= NKDA [verified 09/30]
~ oxycodone 5-10mg PO ×6 [pain ≥4/10 — start 5mg; ↑ to 10mg if unrelieved at 1h — max 6 doses/24h]

professional, formatted, signed — and the before hides: who chooses 5 vs 10? what pain score counts as "pain"? maximum in 24 hours? the ~ forces the condition into the bracket and the ×6 forces the ceiling into the open. the titration rule (5 first, 10 if unrelieved) is stated instead of implied. nothing about the clinical decision changed — it just stopped being invisible.

case 2 — pediatric weight-based dosing (weight + measurement date)

the trap: "dosed per weight" is written once, at ordering time. the weight itself — the number the entire dose depends on — lives somewhere else, measured at some earlier date, possibly estimated. the list carries the conclusion without the premise.

before
DISCHARGE MEDICATIONS — 09/30
  Amoxicillin 250mg/5mL suspension — 1 tsp (5 mL) PO BID × 10 days
  Dx: acute otitis media. Dosed per weight. Counselled on completion.
after
[clinic, 09/30, 10:05, MD:RA]
ALLERGY:
= NKDA [verified 09/30]
= amoxicillin 250mg/5mL PO ×2 [wt: 18kg 2026-09-30 — 45mg/kg/day ÷ BID × 10d]

clean, complete-looking, counselled and signed. hides: which weight? measured when — today, last month, estimated by a parent? what mg/kg basis? the premise is back on the line in the after: 18 kg, measured today, 45 mg/kg/day basis. anyone can re-derive the dose, and anyone can see when the weight goes stale.

case 3 — sliding-scale insulin (reference, don't encode)

the trap: the sliding-scale table looks like the most complete thing on the page — a neat grid of numbers. its completeness is the trap: it hides which protocol version this is, whether it covers meals or only correction, what happens below the bottom row, and where the basal insulin lives. nobody questions a table.

before
INSULIN ORDERS — 09/30
  Per sliding scale (posted protocol):
    BG 150-199 → 2u | 200-249 → 4u | 250-299 → 6u | ≥300 → 8u + notify MD
    Humalog SC with meals and at bedtime
  Lantus 20u SC at bedtime
after
[floor admit, 09/30, 14:22, RN:SK]
ALLERGY:
= NKDA [verified 09/30]
= insulin glargine 20units SC ×1 @bedtime
~ insulin aspart SC ×4 [protocol: unit sliding-scale v3 — correction only, with meals + hs — see chart]
? insulin aspart meal coverage [ordered? — scale reads correction-only — verify prandial plan]

v1 refuses to encode the table — that's the scope wall doing its job (reference a protocol, don't encode it). the ~ carries the version number (v3) so a stale protocol can't hide, and the ? line drags the unasked question — does this cover meals? — into the open. the after is longer than the table and less comfortable, which is the point.

case 4 — incomplete / unknown medication history

the trap: the unknown gets formatted like the known. "likely atorvastatin" sits in a numbered list next to verified entries, and by the third handoff the "likely" has evaporated. formatting confers a certainty the content never had.

before
HOME MEDICATIONS — per patient interview, 09/30, 22:40
  1. Lisinopril 10 mg daily — for blood pressure
  2. Cholesterol pill — white, round tablet (likely atorvastatin)
  3. Aspirin 81 mg daily
  4. Multivitamin daily
Allergies: NKDA (per patient)
after
[ED triage, 09/30, 22:41, RN:MT]
ALLERGY:
? NKDA [pt-reported — unverified]
!! MEDICATION HISTORY UNKNOWN
? lisinopril 10mg PO ×1 [pt-reported dose — unverified — likely for BP]
? atorvastatin ?mg PO ×1 [pt: "white round cholesterol pill" — drug AND dose unverified — DO NOT assume]
= aspirin 81mg PO ×1 [pt brought bottle — verified]
? multivitamin [pt-reported — brand/dose unknown]

the structural flag (!! MEDICATION HISTORY UNKNOWN) says the truth up front: this list is a starting point, not a record. every guess carries its ? and its reason, in the same position on every line, so the uncertainty survives transcription — it's in the grammar now, not in an adjective someone can drop. note the = aspirin: the one verified item is visually distinct from the four uncertain ones. that distinction is the whole deliverable.

case 5 — psychiatric meds (adherence + discontinuation sensitivity)

the trap: psych meds carry two risks ordinary lists don't: invisible non-adherence (the list says "daily," the patient stopped weeks ago) and discontinuation harm (stopping abruptly is itself a clinical event). a standard med list records neither — it records the prescription, which is the one thing everyone already knows.

before
PSYCHIATRIC MEDICATIONS (intake note, 09/30)
  - Sertraline 100 mg qAM — pt reports stopped taking ~3 days ago, "felt fine"
  - Quetiapine 25 mg qhs PRN sleep/agitation
  Plan: restart sertraline prior to discharge
after
[floor admit, 09/30, 14:22, RN:SK]
ALLERGY:
= NKDA [verified 09/30]
∅ sertraline 100mg PO ×1 [abrupt stop ×3d — pt-reported — discontinuation syndrome risk — DO NOT restart at full dose without MD order]
~ quetiapine 25mg PO ×2 [agitation/sleep — max 2/24h]
? sertraline adherence pre-stop [duration of consistent use unknown — verify with pharmacy fill history]

the ∅ marks sertraline inactive with the reason on the line — the discontinuation is treated as the clinical event it is, not as a footnote to a prescription. the bracket blocks the dangerous default (restart at 100 mg) explicitly. the ? line names the missing adherence history and says how to get it. every sentence in the before is true and the note is still dangerous, because the risks are in the whitespace between sentences.

§4 · structure

structural rules — they govern the document, not the line

R1

provenance first. the first non-blank line of every document is the provenance line: who wrote this, where, when. format: [floor admit, 05/10, 14:22, RN:SK]. validators MUST find at least one date token and one author token (RN:SK, MD:RA); otherwise the document is invalid.

R2

allergy block above the list, always. immediately after provenance, the literal heading ALLERGY:, then one or more lines. every allergy entry leads with !!: !! penicillin [anaphylaxis] / !! sulfa [SJS]. no known allergies? write = NKDA with a verification note: = NKDA [verified 09/30]. the block is mandatory — its absence is a validation error, because a missing allergy block is indistinguishable from a forgotten one.

R3

incomplete history is structural, not a footnote. if the medication history is incomplete or unknown, flag it as its own line between the allergy block and the med list: !! LIST INCOMPLETE or !! MEDICATION HISTORY UNKNOWN. a document carrying this flag may have zero med lines — that is valid and honest. guesses formatted as entries are not.

R4

pediatric weight + date in brackets. any line whose dose is weight-derived MUST carry [wt: 18kg 2026-09-30] — weight in kg, then the date it was measured. the mg/kg basis SHOULD be stated too (45mg/kg/day).

R5

one medication per line (expanded mode). inline mode compresses with / separators — see the modes section.

R6

brackets carry meta, never primary data. drug identity, dose, route, and frequency always live outside brackets. brackets carry reactions, hold types, conditions, provenance detail, and explanations.

R7

@ attaches to its own line only. an instruction never applies to the next line.

recommended bracket keywords (conventions, not symbols — parsers treat bracket text as free text but SHOULD recognize these): rx: (prescription basis) · wt: (weight) · hold / resume: · permanent · protocol: (external protocol reference) · verify · pt: (patient-reported) · supp: (supplement) · NKDA.

§6 · modes

two modes: expanded is the record, inline is the compression

expanded mode — one medication per line; the canonical record. inline mode — for notecards, wrist tags, EMS sheets; segments separated by /. same list, both modes, below:

[floor admit, 05/10, 14:22, RN:SK]
ALLERGY:
!! penicillin [anaphylaxis]
!! sulfa [SJS]
? metoprolol succinate 25mg PO ×1  [rx: ×2 — pt taking once daily, clarify intent]
= lisinopril 10mg PO ×1
∅ atorvastatin 40mg PO ×1  [pre-op hold — Dr. Chen — resume POD2]
= levothyroxine 75mcg PO ×1  @fasting / 30min pre-food
∅ metformin 500mg PO ×2  [contrast hold — confirm radiology — reinstate post-procedure]
? aspirin 81mg PO ×1  [pt uncertain if still taking — verify pre-op]
? fish oil 1000mg PO ×2  [supp / pt-reported / unverified]
!! St. John's Wort  [pt-reported / undosed / serotonin + anesthesia interaction — CLARIFY PRE-OP]

read the left margin: ? = ∅ = ∅ ? ? !!. in four seconds you know: two uncertainties, two holds, one critical interaction, everything else verified. that scan is the entire point of verb-first architecture.

§7 · degraded environments

the ascii fallback

photocopy, SMS, paper-only, power outage: every non-ascii symbol gets a plain-ascii equivalent that survives the worst channel. a conformant ascii transcription replaces all non-ascii symbols consistently; validators MUST accept full-ascii documents and MUST warn on mixed mode (rule V7).

unicodeasciinotes
==—
++—
∅XXdouble-cross. never single X (collides with ×), never -.
↑^—
↓v—
~~—
!!!!—
??—
@@—
×NxNlowercase x. x2 = twice daily.
→->dose change: 50mg->25mg.
– / —--free-text dashes only.

the worked example above, transcribed:

[floor admit, 05/10, 14:22, RN:SK]
ALLERGY:
!! penicillin [anaphylaxis]
!! sulfa [SJS]
? metoprolol succinate 25mg PO x1  [rx: x2 -- pt taking once daily, clarify intent]
= lisinopril 10mg PO x1
XX atorvastatin 40mg PO x1  [pre-op hold -- Dr. Chen -- resume POD2]
= levothyroxine 75mcg PO x1  @fasting / 30min pre-food
XX metformin 500mg PO x1  [contrast hold -- confirm radiology -- reinstate post-procedure]
? aspirin 81mg PO x1  [pt uncertain if still taking -- verify pre-op]
? fish oil 1000mg PO x2  [supp / pt-reported / unverified]
!! St. John's Wort  [pt-reported / undosed / serotonin + anesthesia interaction -- CLARIFY PRE-OP]

§5 + §6 · for implementers

parser contract + validity rules

a document is v1-conformant iff: it parses under the grammar (expanded or inline), it satisfies all validity rules and structural rules, it uses only the frozen symbol set (plus ascii equivalents), and it stays inside the scope walls. syntax is the grammar; the V-rules decide validity — a document can parse and still be invalid.

the document shape (expanded mode, EBNF condensed):

document      = provenance , newline ,
                allergy-block , newline ,
                [ history-flag , newline ] ,
                med-list , [ newline ] ;

provenance    = "[" , prov-tag , { "," , prov-tag } , "]" ;
                (* validity (R1): at least one date token and
                   one author token required *)

allergy-block = "ALLERGY:" , newline ,
                ( allergy-entry , { newline , allergy-entry }
                | nkda-line ) ;
allergy-entry = "!!" , space , drug-name ,
                [ space , "[" , free-text , "]" ] ;
nkda-line     = "=" , space , "NKDA" ,
                [ space , "[" , free-text , "]" ] ;

history-flag  = "!!" , space ,
                ( "LIST INCOMPLETE"
                | "MEDICATION HISTORY UNKNOWN" ) ;

med-line      = status , space , entry-body ;
status        = "=" | "+" | "∅" | "↑" | "↓" | "~" | "!!" | "?" ;
entry-body    = drug-name , [ dose ] , [ route ] , [ frequency ] ,
                { "@" , admin-text } , [ "[" , annotation , "]" ] ;

dose          = simple-dose | range-dose | change-dose ;
simple-dose   = number , unit ;              (* 25mg, 75mcg *)
range-dose    = number , "-" , number , unit ;
                (* 5-10mg; ~ lines only *)
change-dose   = number , unit , "→" , number , unit ;
                (* 50mg→25mg; ↑/↓ lines *)
frequency     = "×" , count ;  (* count ≥ 1; ×0 invalid *)

parsing drug-name vs dose: scan tokens left to right after the status symbol; the first token matching number unit (e.g. 25mg, 2puffs) begins the dose. everything before it is the drug name. units and routes are open vocabularies — parsers MUST NOT reject unknown units or routes.

the validity rules:

V1

? requires a bracket. ? was doing double duty (uncertainty vs discrepancy) in early design. resolution: broad ?, mandatory bracket explaining why. ? aspirin 81mg PO ×1 alone is INVALID; ? aspirin 81mg PO ×1 [pt uncertain if still taking — verify pre-op] is valid.

V2

~ requires condition + ceiling. every ~ line MUST carry ×N (maximum doses per 24h) and MUST carry [...] stating the condition. in a ~ line, ×N is the ceiling, never a schedule: ~ oxycodone 5-10mg PO ×6 [pain ≥4/10 — start 5mg, ↑ to 10mg if unrelieved at 1h — max 6 doses/24h]. a ~ line may express a dose range with a hyphen (5-10mg) — the only place a range is allowed.

V3

↑/↓ require old→new. dose-change lines MUST use old-dose → new-dose: ↓ metoprolol succinate 50mg→25mg PO ×1 [tapering — cardiology]. a bracket explaining why SHOULD be present.

V4

∅ requires a hold classification. ∅ means inactive — temporary hold and permanent discontinuation share the symbol, and the bracket MUST say which: [pre-op hold — Dr. Chen — resume POD2] or [discontinued — adverse reaction — permanent]. one symbol, explicit bracket.

V5

!! med lines SHOULD explain. !! St. John's Wort [pt-reported / undosed / serotonin + anesthesia interaction — CLARIFY PRE-OP]. allergy-block !! entries SHOULD carry the reaction in brackets; when the reaction is genuinely unknown, write [reaction unknown] rather than omitting.

V6

×N means per calendar day. ×1 = daily, ×2 = BID, ×3 = TID, ×4 = QID. ×0 is invalid. non-daily schedules are not expressible in ×N — put them in @: @q8h, @q48h, @weekly, @every Monday. (qd/bid/tid/qid themselves are banned from v1.)

V7

mode detection. a document containing any of ∅ ↑ ↓ × → is unicode mode. a document using XX, ^, v, xN, or -> in symbol positions is ascii mode. mixed mode parses but validators MUST warn.

V8

blank lines are permitted between sections and are ignored. leading whitespace on a line is ignored.

what a validator MUST report, at minimum: unknown symbols, missing provenance, missing allergy block, ? without bracket, ~ without ceiling/condition, ∅ without hold classification, ↑/↓ without old→new, weight-based dosing without a wt: bracket, and mixed unicode/ascii mode. a parser SHOULD recover line-by-line: one invalid line must not invalidate the whole document.

pocket validator — a demo of the §5 rules against a single med line. not a clinical tool, not a conformance suite; the rules above are the contract.

§9 · scope

scope walls

IN

general medication reconciliation at transition points.

  • admission, discharge, inter-facility transfer
  • shift handoff, EMS documentation, pre-op reconciliation
  • human-readable med lists on paper, charts, SMS
  • low-resource settings

OUT

specialized domains. for each: write the status line, then [protocol: <name/version>]. reference a protocol; never encode it.

  • oncology regimens and chemotherapy dosing
  • neonatal dosing
  • TPN / compounding
  • infusion titration protocols and sliding-scale tables
  • anything requiring weight/time curves or multi-variable dosing logic

also out — not a scope question, a category question: prescribing and order entry (medscript is a communication layer, not an order format); clinical decision support; terminology coding (RxNorm/SNOMED mapping). medscript must not be mistaken for an order — it describes what a list means, it does not authorize anything. a protocol reference looks like this:

[floor admit, 09/30, 14:22, RN:SK]
ALLERGY:
= NKDA [verified 09/30]
= insulin aspart SC  [protocol: unit sliding-scale v3 — see chart]

§11 · decision log

resolved tensions

#tensionresolutionrule
1? doing double duty (uncertainty vs discrepancy)broad ?, mandatory bracket explanationV1
2hold vs discontinue∅ = inactive, any duration; bracket MUST classify temporary (with resume condition) vs permanentV4
3PRN encoding~ + bracket carries condition + ceiling; ×N on ~ lines = ceiling per 24hV2
4sliding-scale insulin / complex protocolsreference, don't encode: [protocol: <name>]§9
5qd/bid/tid/qidbanned; ×N only; non-daily schedules in @V6
6no known allergies= NKDA in the mandatory allergy blockR2
7inline drug-name truncationallowed but lossy; expanded mode is canonical§6.3
8unit elision in inline modeallowed; omitted unit defaults to mg§6.3
9ascii for ∅XX — never single X, never -§7
10dose range vs dose change- for PRN ranges (5-10mg), → for changes (50mg→25mg)§6.2

§10 · prior art

prior art, stated plainly

adoption

the chokepoint theory

standards don't spread through endorsement. they spread through use — and use concentrates at chokepoints. nursing handoffs are the chokepoint:

that's the adoption vector: make the handoff sheet better, and the standard rides the highest-frequency, most-painful, most-mobile workflow in medicine. a standard spreads through use, not endorsement.

status

frozen as a spec. not validated as anything else.

v1 is frozen as a technical specification (2026-09-30) — complete, internally consistent, parser-implementable. changes require a v2 proposal; do not extend v1 ad hoc.

desk work only — not clinically validated

say it again at the bottom, because the bottom is where people stop reading the top: this is desk work only. it has not been clinically validated, none of the authors are clinicians, and it is not safe to use in patient care on the strength of this document. real-world validation needs real nurses and pharmacists in supervised pilots before any patient ever sees it.

name note: MEDSCRIPT is a working title with trademark baggage in pharmacy services (multiple USPTO filings, past litigation). clearance pending. nothing in the spec depends on the name.

← back to the lab