PMV (Passy Muir Valve) Introduction + Sensory Priming The FEES shows mobile vocal folds bilaterally and bilateral LAR present — PMV candidacy is favorable. TASK DETAIL PMV trial Cuff must be fully deflated before PMV placement; confirm no air leak, adequate SpO₂ Duration target Begin 15–20 min; increase by 10 min each session toward 4–8 hrs/day Rationale PMV restores subglottic pressure → improves laryngeal sensation → reduces penetration/aspiration (O'Connor et al., Heart Lung 2019, PMID 30573194) explain how can i do this procedure aS AN SLP

Reading File
Finding Sources
Finding Sources
Searching PubMed

"Passy Muir valve" tracheostomy dysphagia speech language pathology

Searching the Web

Passy Muir valve PMV trial procedure SLP speech language pathologist step by step placement

Finding Sources
Searching PubMed

"Passy Muir valve" swallowing sensation subglottic pressure

Reading Web Page

https://www.passy-muir.com/wp-content/uploads/2018/10/placem…

Finding Sources
Searching PubMed

"speaking valve" tracheostomy aspiration laryngeal sensation

Reading File
Reading Article

PMID: 30573194

Loading Image
Here is a complete SLP-focused guide for conducting a PMV trial with sensory priming.

PMV Trial Procedure for the SLP

PMV airflow diagram — inhaled air enters via the trach hub; on exhalation the one-way valve closes, redirecting airflow up through the vocal cords and out the mouth
Figure: The PMV opens on inhalation (air → trachea → lungs) and closes on exhalation (air redirected → vocal cords → mouth/nose), restoring transglottic airflow and subglottic pressure. — Tintinalli's Emergency Medicine

Why It Works (The Physiology You Need to Know)

The PMV is a bias-closed, one-way valve. With cuff deflation + PMV in place:
  • Inhalation: valve opens → air flows into trachea/lungs normally
  • Exhalation: valve closes → air must travel upward past the vocal cords, restoring subglottic pressure
  • This restores laryngopharyngeal sensation, improves glottic closure timing, and reduces penetration/aspiration
O'Connor et al. (2019) — the paper you cited — is a systematic review (PMID 30573194, Heart & Lung) that confirmed a meta-analysis OR of 0.12 (95% CI 0.031–0.479) for aspiration reduction with a speaking valve in situ compared to without. It also found significant improvements in olfaction and secretion management. Evidence tier: Systematic Review (Level I).

Pre-Trial Checklist (Before You Walk In)

ItemAction
Physician orderEnsure order is in for "speaking valve evaluation/trial"
Chart reviewTrach brand, size, cuff type, vent status, recent secretion frequency
Trach tube typeFoam-cuffed trach = absolute contraindication for PMV
Glottic patency confirmedFEES showing mobile VFs + bilateral LAR ✅ (your patient qualifies)
Equipment at bedsidePMV, pulse oximeter, suction (oral + tracheal), manual resuscitation bag
Pilot balloon labelAttach the PMV warning label to the pilot balloon line before you start

Step-by-Step: PMV Trial on a Non-Ventilated Patient

Phase 1 — Set Up and Educate

  1. Explain the procedure to the patient and family: what the valve does, how breathing will feel different (harder to exhale at first), what sensations are normal (cough, throat clearing), and STOP criteria.
  2. Position patient upright — minimum 45°, preferably 90°. Upright positioning facilitates lung expansion and reduces aspiration risk.
  3. Baseline vitals — record SpO₂, HR, RR before you touch anything.
  4. Establish a backup communication system (letterboard, paper/pen, eye blink code) in case the patient cannot tolerate the valve.

Phase 2 — Pre-Placement Suctioning

  1. Suction oropharynx first (oral suction) — clear pooled secretions above the cuff before deflating.
  2. Suction trachea as needed.

Phase 3 — Cuff Deflation (critical safety step)

  1. Slowly and completely deflate the cuff using a 10 cc syringe. Gradual deflation gives the patient time to adjust to the shift in airflow and allows residual pooled secretions to be coughed or suctioned away.
  2. Re-assess for suctioning — secretions sitting on top of the cuff will now fall. Suction again if needed.
  3. Confirm upper airway patency — look and listen for:
    • Coughing or throat clearing
    • Vocalizations or reflexive oral movements
    • Exhaled airflow felt at mouth/nose when you hold your hand there
    • This is your glottic patency check: if no airflow reaches the upper airway, the PMV is contraindicated at this time.

Phase 4 — Finger Occlusion Trial (Optional but Recommended)

  1. If the patient is alert enough, occlude the trach hub with a gloved finger momentarily. If the patient can breathe adequately with the hub occluded, they are much more likely to tolerate the PMV. This is a low-risk screening step.

Phase 5 — PMV Placement

  1. Stabilize the trach tube: place one hand on the trach flange/neck plate — do NOT press down on the trachea or create discomfort.
  2. Attach the PMV to the trach hub with the other hand. Give it a ¼ turn clockwise to lock. Do not force it; a forced placement makes removal difficult.
  3. For PMV 2000/2001: attaches directly to the 15 mm hub. For PMV 007: may require an adapter inline.

Phase 6 — Monitoring During the Trial

  1. Continuously monitor for the following STOP criteria — remove the PMV immediately if any occur:
STOP CriteriaAction
SpO₂ drops below 93%Remove PMV, suction, consider cuff re-inflation
HR increases >10 bpm above baselineRemove PMV
RR increases significantly or WOB increasesRemove PMV
Patient reports significant discomfortRemove PMV
Persistent, unrelieved coughingMay indicate upper airway obstruction — remove PMV
PMV pops off with coughSuction, re-assess, replace securely
  1. Do not remove HME (heat-moisture exchanger) and use PMV simultaneously — these are incompatible.
  2. Duration target for first trial: 15–20 minutes as stated in your plan. Increase by ~10 min each subsequent session toward the 4–8 hour/day goal.

Phase 7 — Sensory Priming WITH the PMV In Place

With the PMV restoring transglottic airflow, this is the ideal window for sensory priming:
  • Thermal-tactile stimulation (anterior faucial arches with cold/pressure)
  • Sour bolus stimulation (small sour liquid if safe) — heightened laryngeal chemoreceptor response with restored airflow
  • Effortful throat clear / volitional cough — now possible with subglottic pressure restored
  • Vocalization tasks — sustained /a/, counting — confirms VF adduction and builds sensorimotor relearning
  • FEES or clinical observation of swallow — if dysphagia assessment is the goal, now is the time to trial small boluses (starting with thin liquid via teaspoon or syringe) while observing penetration/aspiration behavior. The restored subglottic pressure should reduce the aspiration events seen without the PMV.

Phase 8 — Removal and Post-Trial

  1. Remove the PMV: stabilize the trach neck plate with one hand → gently pull or twist the PMV off with the other hand. Twist right, not left — leftward rotation can inadvertently unlock the inner cannula.
  2. If the patient did not tolerate: re-inflate the cuff, return to baseline vent/O₂ settings, document STOP criteria met.
  3. Post-trial vitals — confirm return to baseline.
  4. Post-trial suction as needed.
  5. Clean the PMV: mild pure soap + tepid water → rinse thoroughly with cool water → air dry. No hot water, bleach, peroxide, vinegar, alcohol, or autoclaving — these destroy the silastic membrane. PMV is single-patient use; replace if it becomes noisy/vibrating or after ~2 months.

Contraindications — Know These Cold

ContraindicationReason
Foam-cuffed trach (e.g., Bivona)Cuff cannot be fully deflated
Inability to tolerate cuff deflationExhalation pathway is obstructed
Severe upper airway obstructionPMV would cause air trapping
Medical instabilityPhysiologic reserve too low
Severe aspiration riskRelative — weigh risk/benefit; FEES helps stratify
Sleeping patientNever leave PMV in during sleep
Concurrent HME useIncompatible
Active aerosol/nebulizer treatmentRemove PMV first

Ventilated Patients — Key Differences

If your patient is on a ventilator, this involves the RT as a required co-clinician (physician order needed for vent setting changes):
  • Record baseline PIP and tidal volume before cuff deflation
  • After cuff deflation, note the air leak — significant leak confirms upper airway patency
  • Place PMV in-line (between inline suction catheter adapter and flex tubing)
  • Volume augmentation: may increase tidal volume up to +200 cc without physician order; do not exceed baseline PIP
  • Adjust sensitivity to prevent auto-cycling
  • RT manages ventilator; SLP manages valve trial and swallowing assessment simultaneously

Documentation Points

  • Pre/post vitals (SpO₂, HR, RR)
  • Trach tube type, size, cuff status
  • Glottic patency confirmation method (FEES findings as noted, finger occlusion result)
  • Duration tolerated
  • Vocal quality (wet/dry, hoarse, clear)
  • Penetration/aspiration on any bolus trials (PAS scale if FEES done)
  • Patient/family education provided
  • Plan for wear-time progression
  • Any STOP criteria triggered

Evidence Summary

SourceFinding
O'Connor et al., Heart & Lung 2019 [PMID 30573194]Systematic review + meta-analysis: OR 0.12 for aspiration reduction with speaking valve in situ (p=0.003); also improved olfaction, secretion management, ventilator weaning
Cummings OtolaryngologyPMV aids swallowing and prevents aspiration by increasing subglottic pressure
Tintinalli's Emergency MedicinePMV opens on inhalation, closes on exhalation; air directed through VCs; never use with cuffed tube
Your FEES findings (mobile VFs bilaterally + bilateral laryngeal adductor reflex present) place this patient in a favorable candidacy category — the neuromotor substrate for glottic closure is intact, and restoring sensory feedback via subglottic pressure is your primary mechanism of benefit here.

Create a PMV trial protocol checklist PDF for SLP competency verification

Reading File
Running Command

ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace not found"

Running Command

mkdir -p /home/daytona/workspace/pmv-protocol && python3 -c "import reportlab; print('reportlab ok')" && python3 -c "from reportlab.lib.pagesizes import letter; print('ok')"

Writing File

~/pmv-protocol/build_pmv_pdf.py

#!/usr/bin/env python3
"""
PMV Trial Protocol Checklist PDF — SLP Competency Verification
Uses ReportLab for precise clinical-document layout.
"""

from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.lib.units import inch
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether
)
from reportlab.pdfgen import canvas
from reportlab.lib.colors import HexColor
import io, os

# ── Color palette ────────────────────────────────────────────────
DARK_BLUE   = HexColor("#1B3A6B")
MID_BLUE    = HexColor("#2E6DA4")
LIGHT_BLUE  = HexColor("#D6E8F7")
TEAL        = HexColor("#1E7B74")
TEAL_LIGHT  = HexColor("#D0EFED")
RED         = HexColor("#B22222")
RED_LIGHT   = HexColor("#FDE8E8")
AMBER       = HexColor("#A05C00")
AMBER_LIGHT = HexColor("#FFF3CD")
GRAY_DARK   = HexColor("#333333")
GRAY_MED    = HexColor("#666666")
GRAY_LIGHT  = HexColor("#F2F4F6")
WHITE       = colors.white
BLACK       = colors.black

PAGE_W, PAGE_H = letter
MARGIN = 0.55 * inch
INNER_W = PAGE_W - 2 * MARGIN

OUTPUT = "/home/daytona/workspace/pmv-protocol/PMV_Trial_Protocol_SLP_Checklist.pdf"

# ── Style helpers ────────────────────────────────────────────────
def build_styles():
    base = getSampleStyleSheet()
    s = {}

    s["title"] = ParagraphStyle("title",
        fontName="Helvetica-Bold", fontSize=16,
        textColor=WHITE, alignment=TA_CENTER, spaceAfter=2)

    s["subtitle"] = ParagraphStyle("subtitle",
        fontName="Helvetica", fontSize=10,
        textColor=HexColor("#D6E8F7"), alignment=TA_CENTER, spaceAfter=0)

    s["section"] = ParagraphStyle("section",
        fontName="Helvetica-Bold", fontSize=10.5,
        textColor=WHITE, alignment=TA_LEFT,
        spaceBefore=4, spaceAfter=4, leftIndent=4)

    s["body"] = ParagraphStyle("body",
        fontName="Helvetica", fontSize=9,
        textColor=GRAY_DARK, leading=13,
        spaceBefore=1, spaceAfter=1)

    s["body_bold"] = ParagraphStyle("body_bold",
        fontName="Helvetica-Bold", fontSize=9,
        textColor=GRAY_DARK, leading=13)

    s["small"] = ParagraphStyle("small",
        fontName="Helvetica", fontSize=7.5,
        textColor=GRAY_MED, leading=11)

    s["small_bold"] = ParagraphStyle("small_bold",
        fontName="Helvetica-Bold", fontSize=7.5,
        textColor=GRAY_DARK, leading=11)

    s["note"] = ParagraphStyle("note",
        fontName="Helvetica-Oblique", fontSize=8,
        textColor=AMBER, leading=11)

    s["stop"] = ParagraphStyle("stop",
        fontName="Helvetica-Bold", fontSize=8,
        textColor=RED, leading=11)

    s["tbl_hdr"] = ParagraphStyle("tbl_hdr",
        fontName="Helvetica-Bold", fontSize=8.5,
        textColor=WHITE, alignment=TA_CENTER)

    s["tbl_cell"] = ParagraphStyle("tbl_cell",
        fontName="Helvetica", fontSize=8.5,
        textColor=GRAY_DARK, leading=12)

    s["tbl_cell_b"] = ParagraphStyle("tbl_cell_b",
        fontName="Helvetica-Bold", fontSize=8.5,
        textColor=GRAY_DARK, leading=12)

    s["evidence"] = ParagraphStyle("evidence",
        fontName="Helvetica", fontSize=7.5,
        textColor=GRAY_MED, leading=11)

    s["footer"] = ParagraphStyle("footer",
        fontName="Helvetica", fontSize=7,
        textColor=GRAY_MED, alignment=TA_CENTER)

    return s

# ── Checkbox helper ──────────────────────────────────────────────
CHECKBOX = "☐"   # unicode open box

def cb(text, s, indent=0):
    """Return a checkbox paragraph."""
    return Paragraph(f"  {CHECKBOX}  {text}", s)

def cb_crit(text, s):
    """Checkbox for a critical/safety step — bold."""
    return Paragraph(f"&nbsp;&nbsp;{CHECKBOX}&nbsp;&nbsp;<b>{text}</b>", s)

# ── Section header banner ────────────────────────────────────────
def section_banner(label, bg_color, styles):
    data = [[Paragraph(label, styles["section"])]]
    t = Table(data, colWidths=[INNER_W])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), bg_color),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 8),
        ("RIGHTPADDING",  (0,0), (-1,-1), 8),
        ("ROUNDEDCORNERS", [4]),
    ]))
    return t

# ── Two-column checklist table ───────────────────────────────────
def two_col_checks(items_left, items_right, s):
    """Build a 2-column checklist row table."""
    rows = []
    max_len = max(len(items_left), len(items_right))
    for i in range(max_len):
        left  = cb(items_left[i],  s) if i < len(items_left)  else Paragraph("", s)
        right = cb(items_right[i], s) if i < len(items_right) else Paragraph("", s)
        rows.append([left, right])
    col_w = INNER_W / 2 - 2
    t = Table(rows, colWidths=[col_w, col_w])
    t.setStyle(TableStyle([
        ("VALIGN", (0,0), (-1,-1), "TOP"),
        ("TOPPADDING",    (0,0), (-1,-1), 2),
        ("BOTTOMPADDING", (0,0), (-1,-1), 2),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
        ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ]))
    return t

# ── Single-col checklist ─────────────────────────────────────────
def single_col_checks(items, s, critical_indices=None):
    critical_indices = critical_indices or []
    rows = []
    for i, item in enumerate(items):
        if i in critical_indices:
            rows.append([cb_crit(item, s)])
        else:
            rows.append([cb(item, s)])
    t = Table(rows, colWidths=[INNER_W])
    t.setStyle(TableStyle([
        ("VALIGN", (0,0), (-1,-1), "TOP"),
        ("TOPPADDING",    (0,0), (-1,-1), 2),
        ("BOTTOMPADDING", (0,0), (-1,-1), 2),
        ("LEFTPADDING",   (0,0), (-1,-1), 8),
        ("RIGHTPADDING",  (0,0), (-1,-1), 8),
    ]))
    return t

# ── STOP criteria table ──────────────────────────────────────────
def stop_table(styles):
    hdr = [
        Paragraph("STOP CRITERION — Remove PMV Immediately", styles["tbl_hdr"]),
        Paragraph("SLP Action", styles["tbl_hdr"]),
        Paragraph("✓ / N/A", styles["tbl_hdr"]),
    ]
    rows = [
        ["SpO₂ drops below 93% or >4% from baseline",
         "Remove PMV; suction; consider cuff re-inflation; notify team"],
        ["HR increases >10 bpm above resting baseline",
         "Remove PMV; monitor for 2 min; document"],
        ["RR increases significantly or labored WOB",
         "Remove PMV; reposition; reassess upper airway patency"],
        ["Patient reports pain, pressure, or severe discomfort",
         "Remove PMV; do not re-trial same session without MD consult"],
        ["Persistent forceful coughing — PMV not relieving",
         "Remove PMV; consider upper airway obstruction; ENT consult"],
        ["PMV pops off repeatedly with cough",
         "Suction; confirm secure placement; consider trach downsizing"],
        ["Decreasing level of consciousness or agitation",
         "Remove PMV; assess airway; escalate care"],
    ]
    col_w = [INNER_W * 0.40, INNER_W * 0.45, INNER_W * 0.15]
    tbl_rows = [hdr]
    for r in rows:
        tbl_rows.append([
            Paragraph(r[0], styles["tbl_cell"]),
            Paragraph(r[1], styles["tbl_cell"]),
            Paragraph("", styles["tbl_cell"]),  # blank for checkmark
        ])
    t = Table(tbl_rows, colWidths=col_w)
    stripe = RED_LIGHT
    tbl_style = [
        ("BACKGROUND", (0,0), (-1,0), RED),
        ("VALIGN", (0,0), (-1,-1), "TOP"),
        ("GRID", (0,0), (-1,-1), 0.4, HexColor("#CCCCCC")),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
        ("RIGHTPADDING",  (0,0), (-1,-1), 5),
        ("ALIGN", (2,0), (2,-1), "CENTER"),
    ]
    for i in range(1, len(tbl_rows), 2):
        tbl_style.append(("BACKGROUND", (0,i), (-1,i), RED_LIGHT))
    t.setStyle(TableStyle(tbl_style))
    return t

# ── Contraindications table ──────────────────────────────────────
def contraindications_table(styles):
    hdr = [
        Paragraph("Contraindication", styles["tbl_hdr"]),
        Paragraph("Rationale", styles["tbl_hdr"]),
        Paragraph("Confirmed Absent ✓", styles["tbl_hdr"]),
    ]
    rows = [
        ["Foam-cuffed tracheostomy tube (e.g., Bivona)",
         "Cuff cannot be fully deflated; air trapping risk"],
        ["Inability to tolerate cuff deflation",
         "Exhalation through upper airway impossible"],
        ["Severe upper airway obstruction",
         "PMV prevents exhalation; life-threatening air trapping"],
        ["Medical instability / hemodynamic compromise",
         "Insufficient physiologic reserve for trial"],
        ["Laryngectomy (total)",
         "No upper airway communication"],
        ["Concurrent HME in circuit",
         "Blocks exhalation pathway — incompatible with PMV"],
        ["Active nebulizer / aerosol treatment",
         "Medication deposits on valve membrane — remove PMV first"],
        ["Patient asleep or unresponsive",
         "Cannot signal distress; never leave PMV unattended during sleep"],
    ]
    col_w = [INNER_W * 0.33, INNER_W * 0.44, INNER_W * 0.23]
    tbl_rows = [hdr]
    for r in rows:
        tbl_rows.append([
            Paragraph(r[0], styles["tbl_cell_b"]),
            Paragraph(r[1], styles["tbl_cell"]),
            Paragraph("", styles["tbl_cell"]),
        ])
    t = Table(tbl_rows, colWidths=col_w)
    tbl_style = [
        ("BACKGROUND", (0,0), (-1,0), MID_BLUE),
        ("VALIGN", (0,0), (-1,-1), "TOP"),
        ("GRID", (0,0), (-1,-1), 0.4, HexColor("#CCCCCC")),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
        ("RIGHTPADDING",  (0,0), (-1,-1), 5),
        ("ALIGN", (2,0), (2,-1), "CENTER"),
    ]
    for i in range(1, len(tbl_rows), 2):
        tbl_style.append(("BACKGROUND", (0,i), (-1,i), LIGHT_BLUE))
    t.setStyle(TableStyle(tbl_style))
    return t

# ── Competency signature table ───────────────────────────────────
def competency_table(styles):
    rows = [
        [Paragraph("Competency Item", styles["tbl_hdr"]),
         Paragraph("Date Observed", styles["tbl_hdr"]),
         Paragraph("Meets Standard", styles["tbl_hdr"]),
         Paragraph("Supervisor Initials", styles["tbl_hdr"])],
        ["Verifies contraindications + obtains MD order", "", "Yes / No / N/A", ""],
        ["Demonstrates complete cuff deflation technique", "", "Yes / No / N/A", ""],
        ["Confirms upper airway patency (airflow at mouth/nose)", "", "Yes / No / N/A", ""],
        ["Performs secure PMV placement (¼-turn lock)", "", "Yes / No / N/A", ""],
        ["Monitors vitals continuously; identifies STOP criteria", "", "Yes / No / N/A", ""],
        ["Conducts sensory priming / vocalization tasks with PMV", "", "Yes / No / N/A", ""],
        ["Removes PMV safely (stabilizes neck plate; right twist)", "", "Yes / No / N/A", ""],
        ["Documents trial: duration, vitals, voice quality, plan", "", "Yes / No / N/A", ""],
        ["Provides patient + family education", "", "Yes / No / N/A", ""],
        ["Cleans valve correctly; labels single-patient use", "", "Yes / No / N/A", ""],
    ]
    col_w = [INNER_W * 0.40, INNER_W * 0.17, INNER_W * 0.20, INNER_W * 0.23]
    t = Table(rows, colWidths=col_w)
    tbl_style = [
        ("BACKGROUND", (0,0), (-1,0), TEAL),
        ("VALIGN", (0,0), (-1,-1), "MIDDLE"),
        ("GRID", (0,0), (-1,-1), 0.4, HexColor("#CCCCCC")),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
        ("RIGHTPADDING",  (0,0), (-1,-1), 5),
        ("ALIGN", (1,0), (-1,-1), "CENTER"),
        ("FONTNAME",  (0,1), (0,-1), "Helvetica"),
        ("FONTSIZE",  (0,1), (-1,-1), 8.5),
    ]
    for i in range(1, len(rows), 2):
        tbl_style.append(("BACKGROUND", (0,i), (-1,i), TEAL_LIGHT))
    t.setStyle(TableStyle(tbl_style))
    return t

# ── Duration progression table ───────────────────────────────────
def duration_table(styles):
    hdr = [
        Paragraph("Session", styles["tbl_hdr"]),
        Paragraph("Target Duration", styles["tbl_hdr"]),
        Paragraph("Actual Duration", styles["tbl_hdr"]),
        Paragraph("SpO₂ Start / End", styles["tbl_hdr"]),
        Paragraph("Tolerance", styles["tbl_hdr"]),
        Paragraph("SLP Initials", styles["tbl_hdr"]),
    ]
    sessions = [
        ["1 (Initial)", "15–20 min", "", "", "Good / Fair / Poor", ""],
        ["2",           "+10 min",   "", "", "Good / Fair / Poor", ""],
        ["3",           "+10 min",   "", "", "Good / Fair / Poor", ""],
        ["4",           "+10 min",   "", "", "Good / Fair / Poor", ""],
        ["5+",          "→ 4–8 hrs/day target", "", "", "Good / Fair / Poor", ""],
    ]
    col_w = [INNER_W*0.12, INNER_W*0.20, INNER_W*0.17, INNER_W*0.18, INNER_W*0.18, INNER_W*0.15]
    rows = [hdr]
    for r in sessions:
        rows.append([Paragraph(c, styles["tbl_cell"]) for c in r])
    t = Table(rows, colWidths=col_w)
    tbl_style = [
        ("BACKGROUND", (0,0), (-1,0), MID_BLUE),
        ("VALIGN", (0,0), (-1,-1), "MIDDLE"),
        ("GRID", (0,0), (-1,-1), 0.4, HexColor("#CCCCCC")),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
        ("RIGHTPADDING",  (0,0), (-1,-1), 4),
        ("ALIGN", (0,0), (-1,-1), "CENTER"),
    ]
    for i in range(1, len(rows), 2):
        tbl_style.append(("BACKGROUND", (0,i), (-1,i), LIGHT_BLUE))
    t.setStyle(TableStyle(tbl_style))
    return t

# ── Page numbering callback ──────────────────────────────────────
class NumberedCanvas(canvas.Canvas):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._saved_page_states = []

    def showPage(self):
        self._saved_page_states.append(dict(self.__dict__))
        self._startPage()

    def save(self):
        num_pages = len(self._saved_page_states)
        for state in self._saved_page_states:
            self.__dict__.update(state)
            self.draw_page_number(num_pages)
            super().showPage()
        super().save()

    def draw_page_number(self, page_count):
        self.setFont("Helvetica", 7)
        self.setFillColor(GRAY_MED)
        self.drawCentredString(
            PAGE_W / 2, 0.35 * inch,
            f"PMV Trial Protocol — SLP Competency Checklist  |  Page {self._pageNumber} of {page_count}  |  © {2026} — For clinical use only"
        )

# ── Main build ───────────────────────────────────────────────────
def build():
    doc = SimpleDocTemplate(
        OUTPUT,
        pagesize=letter,
        topMargin=MARGIN,
        bottomMargin=0.65 * inch,
        leftMargin=MARGIN,
        rightMargin=MARGIN,
        title="PMV Trial Protocol – SLP Competency Checklist",
        author="Speech-Language Pathology",
        subject="Passy Muir Valve Clinical Protocol",
    )

    S = build_styles()
    story = []

    # ── ① HEADER BANNER ─────────────────────────────────────────
    header_data = [
        [Paragraph("PASSY MUIR VALVE (PMV) TRIAL PROTOCOL", S["title"])],
        [Paragraph("SLP Competency Verification Checklist  |  Non-Ventilated &amp; Ventilated Patients", S["subtitle"])],
    ]
    header_tbl = Table(header_data, colWidths=[INNER_W])
    header_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), DARK_BLUE),
        ("TOPPADDING",    (0,0), (-1,-1), 10),
        ("BOTTOMPADDING", (0,0), (-1,-1), 10),
        ("LEFTPADDING",   (0,0), (-1,-1), 12),
        ("RIGHTPADDING",  (0,0), (-1,-1), 12),
    ]))
    story.append(header_tbl)
    story.append(Spacer(1, 6))

    # ── ② PATIENT / CLINICIAN INFO BOX ──────────────────────────
    info_rows = [
        [Paragraph("Patient Name / MRN:", S["small_bold"]),
         Paragraph("_" * 38, S["small"]),
         Paragraph("Date of Trial:", S["small_bold"]),
         Paragraph("_" * 22, S["small"])],
        [Paragraph("Trach Tube Brand / Size:", S["small_bold"]),
         Paragraph("_" * 38, S["small"]),
         Paragraph("Cuff Type  (circle):", S["small_bold"]),
         Paragraph("Cuffed  /  Cuffless  /  Foam", S["small"])],
        [Paragraph("Evaluating SLP:", S["small_bold"]),
         Paragraph("_" * 38, S["small"]),
         Paragraph("Supervising SLP:", S["small_bold"]),
         Paragraph("_" * 22, S["small"])],
        [Paragraph("Indication:", S["small_bold"]),
         Paragraph("Dysphagia / Communication / Vent weaning / Other: ______", S["small"]),
         Paragraph("Session #:", S["small_bold"]),
         Paragraph("_" * 10, S["small"])],
    ]
    info_col_w = [INNER_W*0.20, INNER_W*0.33, INNER_W*0.20, INNER_W*0.27]
    info_tbl = Table(info_rows, colWidths=info_col_w)
    info_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), GRAY_LIGHT),
        ("GRID",   (0,0), (-1,-1), 0.3, HexColor("#CCCCCC")),
        ("VALIGN", (0,0), (-1,-1), "MIDDLE"),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 6),
        ("RIGHTPADDING",  (0,0), (-1,-1), 6),
    ]))
    story.append(info_tbl)
    story.append(Spacer(1, 6))

    # ── ③ SECTION A: PRE-TRIAL CANDIDACY & CONTRAINDICATIONS ────
    story.append(section_banner("A.  PRE-TRIAL CANDIDACY VERIFICATION", MID_BLUE, S))
    story.append(Spacer(1, 3))
    story.append(Paragraph(
        "<b>All ABSOLUTE contraindications must be confirmed absent before proceeding.</b>",
        S["body"]))
    story.append(Spacer(1, 4))
    story.append(contraindications_table(S))
    story.append(Spacer(1, 5))

    glottic_checks = [
        "FEES or nasolaryngoscopy confirms mobile vocal folds bilaterally",
        "Bilateral laryngeal adductor reflex (LAR) present",
        "Upper airway patent: adequate space between trach OD and tracheal wall for exhalation",
        "Physician order obtained for speaking valve evaluation / trial",
        "Recent suctioning frequency and secretion quality reviewed with bedside nurse",
    ]
    story.append(Paragraph("<b>Glottic Patency & Candidacy Confirmation:</b>", S["body"]))
    story.append(single_col_checks(glottic_checks, S["body"], critical_indices=[0,1,2]))
    story.append(Spacer(1, 6))

    # ── ④ SECTION B: PRE-PLACEMENT PREPARATION ──────────────────
    story.append(section_banner("B.  PRE-PLACEMENT PREPARATION", MID_BLUE, S))
    story.append(Spacer(1, 3))

    prep_items = [
        "Equipment verified at bedside: PMV, pulse oximeter, oral suction, tracheal suction, manual resuscitation bag",
        "Pilot balloon safety label applied to trach pilot line (from PMV package)",
        "Patient positioned UPRIGHT (≥45°; prefer 90°) — optimizes lung expansion and reduces aspiration risk",
        "Baseline vitals recorded: SpO₂ _____ HR _____ RR _____",
        "Backup AAC / communication method established (letterboard / paper / eye blink / high-tech AAC)",
        "Patient and family education provided: valve mechanics, airflow change, expected sensations, STOP signals",
        "HME removed from circuit (incompatible with PMV)",
        "No active nebulizer or aerosol treatment in progress",
    ]
    story.append(single_col_checks(prep_items, S["body"], critical_indices=[2, 3]))
    story.append(Spacer(1, 6))

    # ── ⑤ SECTION C: CUFF DEFLATION & AIRWAY PATENCY ────────────
    story.append(section_banner("C.  CUFF DEFLATION & UPPER AIRWAY PATENCY CHECK  ★ SAFETY CRITICAL", RED, S))
    story.append(Spacer(1, 3))
    story.append(Paragraph(
        "<b>★  The cuff MUST be FULLY deflated before PMV placement. Partial deflation = air trapping = life threat.</b>",
        S["stop"]))
    story.append(Spacer(1, 4))

    cuff_items = [
        "Oral/pharyngeal suction performed (clears pooled secretions ABOVE cuff before deflation)",
        "Tracheal suction performed as needed",
        "SLOW, COMPLETE cuff deflation via 10 cc syringe — pilot balloon fully collapsed",
        "Cuff deflation confirmed: pilot balloon flat, cuff palpation, or manometer reads 0 cm H₂O",
        "Post-deflation suctioning performed — secretions that were sitting on cuff now accessible",
        "UPPER AIRWAY PATENCY CONFIRMED: exhaled airflow felt at mouth/nose on patient exhalation",
        "   Alternative confirmation: spontaneous cough, vocalization, throat clearing, or reflexive oral movement observed",
        "Finger occlusion trial performed (if patient alert): patient tolerates hub occlusion without distress",
        "SpO₂ remains acceptable (≥93%) after cuff deflation alone: SpO₂ post-deflation _____",
    ]
    story.append(single_col_checks(cuff_items, S["body"], critical_indices=[2,3,5]))
    story.append(Spacer(1, 6))

    # ── ⑥ SECTION D: PMV PLACEMENT ──────────────────────────────
    story.append(section_banner("D.  PMV PLACEMENT (NON-VENTILATED PATIENT)", MID_BLUE, S))
    story.append(Spacer(1, 3))

    placement_items = [
        "PMV model identified: PMV 2000 (aqua) / PMV 2001 (white) — attaches directly to 15 mm hub",
        "   OR  PMV 007 (aqua/clear) — requires adapter inline between suction catheter and flex tubing",
        "Non-dominant hand stabilizes trach flange/neck plate WITHOUT downward pressure on trachea",
        "Dominant hand attaches PMV to trach hub — GENTLE placement, no force",
        "PMV locked with ¼-turn CLOCKWISE — confirmed seated securely",
        "Valve opening orientation checked: bias-closed position confirmed (valve does not flap open at rest)",
        "Post-placement SpO₂, HR, RR recorded immediately: SpO₂ _____ HR _____ RR _____",
        "Patient able to vocalize or phonate — voice quality noted: ☐ Clear  ☐ Wet/gurgly  ☐ Hoarse  ☐ Absent",
    ]
    story.append(single_col_checks(placement_items, S["body"], critical_indices=[2,3,4]))
    story.append(Spacer(1, 4))

    story.append(Paragraph(
        "<b>Ventilated patients — additional steps (RT co-management required):</b>", S["body_bold"]))
    vent_items = [
        "Baseline PIP and exhaled tidal volume recorded pre-deflation",
        "Post-deflation air leak noted (confirms upper airway patency for ventilated patient)",
        "PMV placed in-line: removed 15 mm adapter between inline suction catheter and 6-inch flex tubing → replaced with PMV",
        "Ventilator settings adjusted by RT: volume augmentation ≤+200 cc; do NOT exceed baseline PIP",
        "Sensitivity adjusted to prevent auto-cycling",
        "RT and SLP monitoring simultaneously — clear roles established",
    ]
    story.append(single_col_checks(vent_items, S["body"], critical_indices=[1,2,3]))
    story.append(Spacer(1, 6))

    # ── ⑦ SECTION E: MONITORING & STOP CRITERIA ─────────────────
    story.append(section_banner("E.  CONTINUOUS MONITORING & STOP CRITERIA", RED, S))
    story.append(Spacer(1, 3))
    story.append(Paragraph(
        "Monitor continuously throughout trial. Remove PMV immediately if ANY criterion below is met.",
        S["body"]))
    story.append(Spacer(1, 4))
    story.append(stop_table(S))
    story.append(Spacer(1, 6))

    # ── ⑧ SECTION F: SENSORY PRIMING & SWALLOWING ───────────────
    story.append(section_banner("F.  SENSORY PRIMING & SWALLOWING ASSESSMENT WITH PMV IN SITU", TEAL, S))
    story.append(Spacer(1, 3))
    story.append(Paragraph(
        "With PMV restoring subglottic pressure and transglottic airflow, the following priming tasks can be performed. "
        "Restored subglottic pressure improves laryngeal chemoreceptor and mechanoreceptor sensitivity, "
        "enhancing glottic closure timing during swallowing (O'Connor et al., Heart &amp; Lung 2019 — OR 0.12 for aspiration reduction, 95% CI 0.031–0.479, p=0.003).",
        S["body"]))
    story.append(Spacer(1, 4))

    priming_items = [
        "Thermal-tactile stimulation (anterior faucial arches — cold probe/spoon) — heightens swallow trigger",
        "Sour bolus stimulation (small sour liquid if deemed safe) — enhances laryngeal chemoreceptor response",
        "Volitional cough task — effortful cough now possible with subglottic pressure restored; assess cough strength",
        "Throat clear task — volitional glottic closure trial; note success and quality",
        "Sustained vocalization /a/ (3–5 sec) — confirms VF adduction; documents voice quality",
        "Counting / sustained phonation — sensorimotor integration + respiratory support for speech",
        "Trial swallows (if indicated by FEES/clinical findings):",
        "   Thin liquid — 5 mL teaspoon/syringe × 3 trials — observe for cough, wet voice, SpO₂ change",
        "   Nectar or pudding bolus — per clinical judgment / FEES findings",
        "Penetration-Aspiration Scale (PAS) rating post-swallow trial: PAS _____",
        "Patient/family instructed: valve restores taste/smell — olfaction often improved same session",
    ]
    story.append(single_col_checks(priming_items, S["body"], critical_indices=[2,3]))
    story.append(Spacer(1, 6))

    # ── ⑨ SECTION G: PMV REMOVAL & POST-TRIAL ───────────────────
    story.append(section_banner("G.  PMV REMOVAL & POST-TRIAL TASKS", MID_BLUE, S))
    story.append(Spacer(1, 3))

    removal_items = [
        "Trial duration achieved or STOP criteria prompted early removal — duration: _____ minutes",
        "Stabilize trach neck plate with non-dominant hand",
        "Remove PMV with dominant hand: GENTLE pull or twist to the RIGHT (not left — leftward unlocks inner cannula)",
        "If poor tolerance / STOP criteria: re-inflate cuff; return ventilator to baseline settings",
        "Post-trial vitals recorded: SpO₂ _____ HR _____ RR _____ (confirm return to baseline)",
        "Post-trial suction as needed",
        "Ventilator settings returned to baseline by RT (if ventilated)",
        "PMV cleaning: pure mild soap + tepid water → thorough rinse in COOL water → air dry in open container",
        "   ★  No hot water / bleach / peroxide / vinegar / alcohol / autoclaving — damages silastic membrane",
        "PMV labeled with patient ID + date opened; single-patient use only; replace if noisy/vibrating or after ~2 months",
        "Warning signs placed: 'CUFF MUST BE DEFLATED FOR PMV USE' — at head of bed AND on pilot line",
    ]
    story.append(single_col_checks(removal_items, S["body"], critical_indices=[2,8]))
    story.append(Spacer(1, 6))

    # ── ⑩ SECTION H: DURATION PROGRESSION LOG ───────────────────
    story.append(section_banner("H.  SESSION DURATION PROGRESSION LOG", MID_BLUE, S))
    story.append(Spacer(1, 3))
    story.append(Paragraph(
        "Begin 15–20 min (Session 1). Increase by ~10 min each subsequent session toward goal of 4–8 hrs/day.",
        S["body"]))
    story.append(Spacer(1, 4))
    story.append(duration_table(S))
    story.append(Spacer(1, 6))

    # ── ⑪ SECTION I: DOCUMENTATION CHECKLIST ────────────────────
    story.append(section_banner("I.  DOCUMENTATION CHECKLIST (Post-Trial)", TEAL, S))
    story.append(Spacer(1, 3))

    doc_items_left = [
        "Pre/post vitals (SpO₂, HR, RR)",
        "Trach tube brand, size, cuff type/status",
        "Glottic patency confirmation method",
        "PMV model used + placement technique",
        "Duration tolerated",
    ]
    doc_items_right = [
        "Voice quality (wet/dry/hoarse/clear/absent)",
        "Penetration/Aspiration Scale (PAS) rating",
        "Any STOP criteria triggered + action taken",
        "Patient/family education delivered",
        "Plan: next session duration target + goals",
    ]
    story.append(two_col_checks(doc_items_left, doc_items_right, S["body"]))
    story.append(Spacer(1, 6))

    # ── ⑫ SECTION J: SLP COMPETENCY SIGN-OFF ────────────────────
    story.append(section_banner("J.  SLP COMPETENCY SIGN-OFF", TEAL, S))
    story.append(Spacer(1, 3))
    story.append(Paragraph(
        "All new SLPs or SLPs new to trach/vent populations must be observed by a senior clinician until competency is established. "
        "Mark each item with date observed. Supervisor signs upon satisfactory performance.",
        S["body"]))
    story.append(Spacer(1, 4))
    story.append(competency_table(S))
    story.append(Spacer(1, 5))

    sig_rows = [
        [Paragraph("Clinician Signature:", S["small_bold"]),
         Paragraph("_" * 40, S["small"]),
         Paragraph("Date Competency Achieved:", S["small_bold"]),
         Paragraph("_" * 20, S["small"])],
        [Paragraph("Supervisor Signature:", S["small_bold"]),
         Paragraph("_" * 40, S["small"]),
         Paragraph("Credentials / Role:", S["small_bold"]),
         Paragraph("_" * 20, S["small"])],
    ]
    sig_tbl = Table(sig_rows, colWidths=[INNER_W*0.20, INNER_W*0.33, INNER_W*0.25, INNER_W*0.22])
    sig_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), GRAY_LIGHT),
        ("GRID", (0,0), (-1,-1), 0.3, HexColor("#CCCCCC")),
        ("TOPPADDING", (0,0), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,-1), 6),
        ("LEFTPADDING", (0,0), (-1,-1), 6),
        ("RIGHTPADDING", (0,0), (-1,-1), 6),
        ("VALIGN", (0,0), (-1,-1), "MIDDLE"),
    ]))
    story.append(sig_tbl)
    story.append(Spacer(1, 8))

    # ── ⑬ EVIDENCE FOOTER ────────────────────────────────────────
    story.append(HRFlowable(width=INNER_W, thickness=0.5, color=GRAY_MED))
    story.append(Spacer(1, 4))
    story.append(Paragraph(
        "<b>Evidence Base:</b>  O'Connor LR, Morris NR, Paratz J. Physiological and clinical outcomes associated with use of one-way speaking valves "
        "on tracheostomised patients: A systematic review. <i>Heart Lung.</i> 2019;48(4):356–364. PMID 30573194 "
        "[Systematic Review — OR 0.12 for aspiration reduction with speaking valve in situ, 95% CI 0.031–0.479, p=0.003].  "
        "Cummings Otolaryngology (7th ed.): PMV aids swallowing and prevents aspiration by increasing subglottic pressure.  "
        "Tintinalli's Emergency Medicine (9th ed.): PMV one-way valve physiology and contraindications.",
        S["evidence"]))
    story.append(Spacer(1, 3))
    story.append(Paragraph(
        "This checklist is for clinical and educational use. It does not replace institutional policy, physician orders, or direct clinical judgment. "
        "Always follow your facility's tracheostomy and ventilator management protocols.",
        S["evidence"]))

    doc.build(story, canvasmaker=NumberedCanvas)
    print(f"PDF written to: {OUTPUT}")

if __name__ == "__main__":
    build()
Running Command

cd /home/daytona/workspace/pmv-protocol && python3 build_pmv_pdf.py 2>&1

Your credits are exhausted. Your daily credits reset tomorrow, or you can purchase a top-up for more.
This is a shared conversation. Sign in to Orris to start your own chat.