why do i want to lay on the bed all the time? it's already a year
Find recent medical research on prolonged fatigue causes
chronic fatigue syndrome etiology pathophysiology
prolonged fatigue causes depression thyroid anemia
recent research prolonged fatigue causes 2024 2025
PMID: 39353473
PMID: 38016575
PMID: 39354352
fatigue depression hypothyroidism vitamin D deficiency
fatigue etiology adults vitamin D iron deficiency
long COVID fatigue post-viral syndrome mechanism treatment
| Cause | Key Takeaway |
|---|---|
| Post-viral / Long COVID | ~50% of long COVID patients meet ME/CFS criteria |
| Neuroinflammation | Brain changes are measurable - fatigue is biological |
| Immune dysregulation | Autoantibodies and cytokine disruption are real factors |
| Mitochondrial dysfunction | Cellular energy production may be impaired |
| Classic causes (thyroid, anemia, depression, vit D) | Still the most common and most treatable - must be ruled out first |
Bloodwork are all fine.
chronic fatigue normal bloodwork sleep disturbance cognitive symptoms
ME/CFS diagnosis criteria fatigue brain fog without depression
chronic fatigue syndrome normal bloodwork brain fog sleep problems diagnosis 2024 2025
| Requirement | Your Status |
|---|---|
| Substantial fatigue lasting 6+ months | Yes - 1 year |
| Unrefreshing sleep | Yes |
| Cognitive impairment (brain fog) | Yes |
| Not explained by other conditions | Bloodwork normal |
Create a symptom tracker to document daily energy patterns
mkdir -p /home/daytona/workspace/symptom-tracker && ls /home/daytona/workspace/symptom-tracker
~/symptom-tracker/generate.js
const {
Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
HeadingLevel, AlignmentType, BorderStyle, WidthType, VerticalAlign,
ShadingType, LevelFormat, PageNumber, Header, Footer, PageBreak
} = require('docx');
const fs = require('fs');
// ─── Color palette ─────────────────────────────────────────────────────────
const TEAL = "2A7A8C";
const TEAL_LIGHT = "D6EEF2";
const SOFT_BLUE = "EBF4F6";
const GREY_LIGHT = "F5F5F5";
const GREY_MID = "DDDDDD";
const WHITE = "FFFFFF";
const BLACK = "222222";
// ─── Helpers ───────────────────────────────────────────────────────────────
function noBorder() {
return { style: BorderStyle.NONE, size: 0, color: "FFFFFF" };
}
function thinBorder() {
return { style: BorderStyle.SINGLE, size: 4, color: GREY_MID };
}
function cell(children, opts = {}) {
return new TableCell({
children: Array.isArray(children) ? children : [children],
verticalAlign: VerticalAlign.CENTER,
shading: opts.shading ? { fill: opts.shading, type: ShadingType.CLEAR, color: "auto" } : undefined,
width: opts.width ? { size: opts.width, type: WidthType.DXA } : undefined,
columnSpan: opts.span,
borders: opts.borders || {
top: thinBorder(), bottom: thinBorder(), left: thinBorder(), right: thinBorder()
},
margins: { top: 80, bottom: 80, left: 140, right: 140 }
});
}
function headerCell(text, shade = TEAL) {
return cell(
new Paragraph({
alignment: AlignmentType.CENTER,
children: [new TextRun({ text, bold: true, color: WHITE, size: 18, font: "Arial" })]
}),
{ shading: shade }
);
}
function labelCell(text, shade = SOFT_BLUE, bold = false) {
return cell(
new Paragraph({
children: [new TextRun({ text, bold, color: BLACK, size: 18, font: "Arial" })]
}),
{ shading: shade }
);
}
function inputCell(placeholder = "", shade = WHITE, span = 1) {
return cell(
new Paragraph({
children: [new TextRun({ text: placeholder, color: "AAAAAA", size: 18, font: "Arial", italics: !!placeholder })]
}),
{ shading: shade, span }
);
}
function ratingCell(shade = WHITE) {
return cell(
new Paragraph({
alignment: AlignmentType.CENTER,
children: [new TextRun({ text: " 1 2 3 4 5 6 7 8 9 10", color: "999999", size: 16, font: "Arial" })]
}),
{ shading: shade }
);
}
function sectionHeading(text) {
return new Paragraph({
spacing: { before: 280, after: 80 },
children: [
new TextRun({ text: " " + text + " ", bold: true, color: WHITE, size: 20, font: "Arial",
highlight: undefined, shading: { fill: TEAL, type: ShadingType.CLEAR } })
],
shading: { fill: TEAL, type: ShadingType.CLEAR, color: "auto" }
});
}
function smallNote(text) {
return new Paragraph({
spacing: { before: 40, after: 100 },
children: [new TextRun({ text, color: "777777", size: 16, italics: true, font: "Arial" })]
});
}
function spacer(before = 160, after = 80) {
return new Paragraph({ spacing: { before, after }, children: [new TextRun("")] });
}
// ─── Build daily log table ─────────────────────────────────────────────────
function buildDailyTable() {
const colWidths = [2400, 6626]; // label | input (total ~9026 for A4)
function row2(label, inputText = "", labelShade = SOFT_BLUE, inputShade = WHITE) {
return new TableRow({
children: [
labelCell(label, labelShade),
inputCell(inputText, inputShade)
]
});
}
function ratingRow(label, labelShade = SOFT_BLUE) {
return new TableRow({
children: [
labelCell(label, labelShade),
ratingCell(WHITE)
]
});
}
function sectionRow(text) {
return new TableRow({
children: [
cell(
new Paragraph({
alignment: AlignmentType.LEFT,
children: [new TextRun({ text, bold: true, color: WHITE, size: 18, font: "Arial" })]
}),
{ shading: TEAL, span: 2 }
)
]
});
}
function subheadRow(text) {
return new TableRow({
children: [
cell(
new Paragraph({
children: [new TextRun({ text, bold: true, color: TEAL, size: 18, font: "Arial" })]
}),
{ shading: TEAL_LIGHT, span: 2 }
)
]
});
}
return new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
columnWidths: colWidths,
rows: [
// ── Header ──
new TableRow({
children: [
cell(
new Paragraph({
alignment: AlignmentType.CENTER,
children: [new TextRun({ text: "DATE: _____ / _____ / _______ DAY #: _______", bold: true, size: 22, color: BLACK, font: "Arial" })]
}),
{ shading: TEAL_LIGHT, span: 2 }
)
]
}),
// ── MORNING ──
sectionRow("MORNING (upon waking)"),
ratingRow("Energy level on waking (1 = exhausted, 10 = great)"),
row2("Sleep quality last night", "Circle: Very Poor / Poor / Fair / Good / Excellent"),
row2("Hours slept", "_____ hrs"),
row2("Woke up how many times?", "_____ times"),
row2("How do you feel vs yesterday?", "Circle: Much Worse / Worse / Same / Better / Much Better"),
row2("Morning symptoms", "e.g. headache, heavy limbs, dizziness..."),
// ── MIDDAY ──
sectionRow("MIDDAY (around noon)"),
ratingRow("Energy level now (1 = exhausted, 10 = great)"),
row2("Activity done this morning", "e.g. light walk, desk work, resting..."),
row2("Brain fog / concentration", "Circle: None / Mild / Moderate / Severe"),
row2("Midday symptoms", "e.g. brain fog, nausea, pain..."),
// ── AFTERNOON ──
sectionRow("AFTERNOON (3-5 PM)"),
ratingRow("Energy level now (1 = exhausted, 10 = great)"),
row2("Did you rest or nap?", "Circle: No / Short rest / Nap _____ min"),
row2("Post-exertion crash?", "Circle: None / Mild / Moderate / Severe"),
row2("Afternoon symptoms", ""),
// ── EVENING ──
sectionRow("EVENING (wind-down)"),
ratingRow("Energy level now (1 = exhausted, 10 = great)"),
row2("Activity done today (total)", "e.g. mostly rested / short walk / light chores..."),
row2("Mood today", "Circle: Low / Neutral / Okay / Good"),
row2("Stress level today", "Circle: None / Low / Moderate / High"),
row2("Evening symptoms", ""),
// ── SLEEP PREP ──
sectionRow("BEDTIME"),
row2("Bedtime", "_____ : _____ PM/AM"),
row2("Screen time before bed", "_____ min"),
row2("Caffeine today?", "Circle: None / 1 cup / 2+ cups | Last cup at: _____"),
row2("Medications / supplements taken", ""),
// ── DAILY TOTALS ──
sectionRow("DAILY SUMMARY"),
ratingRow("Overall energy today (1 = exhausted, 10 = great)"),
ratingRow("Overall pain / discomfort (1 = none, 10 = severe)"),
row2("Steps / movement today", "_____ steps OR _____ min of activity"),
row2("Fluids consumed", "_____ glasses of water"),
row2("Meals / appetite", "Circle: Poor / Fair / Normal / Good"),
row2("One word to describe today", ""),
new TableRow({
children: [
cell(
new Paragraph({
children: [new TextRun({ text: "Notes / observations for doctor", bold: true, color: BLACK, size: 18, font: "Arial" })]
}),
{ shading: TEAL_LIGHT }
),
inputCell("Anything unusual? Triggers noticed? New symptoms?", WHITE)
]
}),
new TableRow({
tableHeader: false,
children: [
cell(
new Paragraph({ children: [new TextRun({ text: "", size: 18 })] }),
{ shading: WHITE, span: 2, borders: { top: noBorder(), bottom: thinBorder(), left: thinBorder(), right: thinBorder() } }
)
],
height: { value: 600, rule: "exact" }
})
]
});
}
// ─── Weekly summary table ─────────────────────────────────────────────────
function buildWeeklySummary() {
const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
const headerRow = new TableRow({
children: [
headerCell("Metric", TEAL),
...days.map(d => headerCell(d, TEAL))
]
});
function metricRow(label, shade = WHITE) {
return new TableRow({
children: [
labelCell(label, SOFT_BLUE, true),
...days.map(() => inputCell("", shade))
]
});
}
return new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
rows: [
headerRow,
metricRow("Morning energy (1-10)"),
metricRow("Avg energy (1-10)"),
metricRow("Sleep hours"),
metricRow("Sleep quality (1-10)"),
metricRow("Brain fog (1-10)"),
metricRow("Pain (1-10)"),
metricRow("Activity level (1-10)"),
metricRow("Post-exertion crash?"),
metricRow("Mood (1-10)"),
new TableRow({
children: [
labelCell("Best time of day", SOFT_BLUE, true),
...days.map(() => inputCell("", WHITE))
]
}),
new TableRow({
children: [
labelCell("Worst time of day", SOFT_BLUE, true),
...days.map(() => inputCell("", WHITE))
]
}),
]
});
}
// ─── How to use guide ─────────────────────────────────────────────────────
function buildHowToUse() {
const items = [
["Fill in daily", "Complete each section at the time of day shown (morning, midday, afternoon, evening, bedtime). Takes about 3-5 minutes total per day."],
["Be consistent", "Track every day, even good ones. Patterns only emerge from continuous data."],
["Rate honestly", "The 1-10 scales are relative to YOUR normal, not a healthy person. 5 = your average."],
["Post-exertion watch", "If you feel worse 12-48 hours after activity, note it in 'Post-exertion crash'. This is a key diagnostic clue."],
["Bring to appointments", "Print 2-4 weeks of logs before seeing your doctor. The weekly summary table is especially useful for spotting trends."],
["Notice patterns", "Look for: time-of-day trends, activity-crash cycles, sleep vs energy links, food or stress triggers."],
];
const rows = items.map(([title, desc]) =>
new TableRow({
children: [
labelCell(title, TEAL_LIGHT, true),
cell(
new Paragraph({ children: [new TextRun({ text: desc, size: 18, font: "Arial", color: BLACK })] }),
{ shading: WHITE }
)
]
})
);
return new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
rows: [
new TableRow({
children: [
cell(
new Paragraph({
alignment: AlignmentType.CENTER,
children: [new TextRun({ text: "HOW TO USE THIS TRACKER", bold: true, size: 20, color: WHITE, font: "Arial" })]
}),
{ shading: TEAL, span: 2 }
)
]
}),
...rows
]
});
}
// ─── Assemble document ────────────────────────────────────────────────────
const doc = new Document({
styles: {
default: {
document: { run: { font: "Arial", size: 20, color: BLACK } }
},
paragraphStyles: [
{
id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal", quickFormat: true,
run: { size: 36, bold: true, font: "Arial", color: TEAL },
paragraph: { spacing: { before: 200, after: 160 }, outlineLevel: 0 }
},
{
id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal", quickFormat: true,
run: { size: 26, bold: true, font: "Arial", color: TEAL },
paragraph: { spacing: { before: 200, after: 120 }, outlineLevel: 1 }
}
]
},
sections: [
// ── Section 1: Cover / How-to ──────────────────────────────────────
{
properties: {},
children: [
spacer(0, 200),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { before: 0, after: 60 },
children: [new TextRun({ text: "Daily Energy & Symptom Tracker", bold: true, size: 48, font: "Arial", color: TEAL })]
}),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { before: 0, after: 60 },
children: [new TextRun({ text: "For Prolonged Fatigue, ME/CFS & Chronic Illness", size: 24, font: "Arial", color: "555555", italics: true })]
}),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { before: 0, after: 400 },
children: [new TextRun({ text: "Name: ________________________________ Start Date: _______________", size: 22, font: "Arial", color: "333333" })]
}),
buildHowToUse(),
spacer(300, 200),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { before: 0, after: 200 },
children: [new TextRun({ text: "Tip: Print multiple copies of the Daily Log page and fill one per day.", size: 18, font: "Arial", color: "777777", italics: true })]
}),
// Page break before daily log
new Paragraph({ children: [new PageBreak()] }),
]
},
// ── Section 2: Daily Log ───────────────────────────────────────────
{
properties: {},
children: [
new Paragraph({
heading: HeadingLevel.HEADING_1,
spacing: { before: 0, after: 160 },
children: [new TextRun({ text: "Daily Log", bold: true, size: 36, font: "Arial", color: TEAL })]
}),
smallNote("Fill in each section at the time of day shown. Ratings are 1 (worst) to 10 (best) unless noted otherwise."),
spacer(80, 80),
buildDailyTable(),
spacer(200, 100),
new Paragraph({ children: [new PageBreak()] }),
]
},
// ── Section 3: Weekly Summary ──────────────────────────────────────
{
properties: {},
children: [
new Paragraph({
heading: HeadingLevel.HEADING_1,
spacing: { before: 0, after: 160 },
children: [new TextRun({ text: "Weekly Summary", bold: true, size: 36, font: "Arial", color: TEAL })]
}),
smallNote("Week of: _______________ | Fill in your daily scores at the end of each week to track trends."),
spacer(80, 80),
buildWeeklySummary(),
spacer(240, 160),
new Paragraph({
heading: HeadingLevel.HEADING_2,
children: [new TextRun({ text: "Weekly Observations", bold: true, size: 26, color: TEAL, font: "Arial" })]
}),
smallNote("Look back at the week. What patterns stand out? Were there triggers? Best/worst days?"),
new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
rows: [
new TableRow({
children: [
cell(new Paragraph({ children: [new TextRun({ text: "Best day of week & why:", size: 18, font: "Arial" })] }), { shading: SOFT_BLUE }),
inputCell("", WHITE),
]
}),
new TableRow({
children: [
cell(new Paragraph({ children: [new TextRun({ text: "Worst day of week & why:", size: 18, font: "Arial" })] }), { shading: SOFT_BLUE }),
inputCell("", WHITE),
]
}),
new TableRow({
children: [
cell(new Paragraph({ children: [new TextRun({ text: "Possible triggers noticed:", size: 18, font: "Arial" })] }), { shading: SOFT_BLUE }),
inputCell("e.g. poor sleep, overactivity, stress, food...", WHITE),
]
}),
new TableRow({
children: [
cell(new Paragraph({ children: [new TextRun({ text: "Activity vs energy relationship:", size: 18, font: "Arial" })] }), { shading: SOFT_BLUE }),
inputCell("Did more activity lead to a crash 1-2 days later?", WHITE),
]
}),
new TableRow({
children: [
cell(new Paragraph({ children: [new TextRun({ text: "Questions for my doctor:", size: 18, font: "Arial" })] }), { shading: SOFT_BLUE }),
inputCell("", WHITE),
]
}),
new TableRow({
children: [
cell(new Paragraph({ children: [new TextRun({ text: "Overall trend vs last week:", size: 18, font: "Arial" })] }), { shading: SOFT_BLUE }),
cell(
new Paragraph({
children: [new TextRun({ text: "Circle: Worse / Same / Slightly Better / Better / Much Better", color: "999999", size: 18, italics: true, font: "Arial" })]
}),
{ shading: WHITE }
),
]
}),
]
}),
spacer(200, 100),
]
}
]
});
Packer.toBuffer(doc).then(buffer => {
fs.writeFileSync("/home/daytona/workspace/symptom-tracker/Daily_Energy_Symptom_Tracker.docx", buffer);
console.log("Done.");
});
cd /home/daytona/workspace/symptom-tracker && node generate.js 2>&1
python /home/daytona/skills/docx/scripts/office/validate.py /home/daytona/workspace/symptom-tracker/Daily_Energy_Symptom_Tracker.docx 2>&1
cd /home/daytona/workspace/symptom-tracker && python3 -c " import zipfile, sys try: with zipfile.ZipFile('Daily_Energy_Symptom_Tracker.docx') as z: names = z.namelist() print('Valid ZIP. Files:', names[:8]) xml = z.read('word/document.xml').decode('utf-8', errors='replace') print('document.xml size:', len(xml), 'chars') print('First 300 chars:', xml[:300]) except Exception as e: print('ERROR:', e) "
Daily Energy Symptom Tracker
Word Document · DOCX
Find an ME/CFS specialist or fatigue clinic
ME/CFS specialist clinics NHS UK 2024 2025 referral
ME/CFS fatigue clinic UK list NICE guidelines referral 2025
https://meassociation.org.uk/2025/07/nice-release-a-new-clin…
ME CFS specialist clinic finder UK private NHS list meassociation
| Region | Service | Contact |
|---|---|---|
| London (North/Central) | ME/CFS & Fibromyalgia Service, Royal London Hospital for Integrated Medicine (UCLH) | Via NHS e-Referral |
| London (East) | ME/CFS Service, Homerton Healthcare NHS Trust | Via GP referral |
| Essex / East of England | National CFS Diagnostic & Specialist Rehabilitation Service, Queen's Hospital Romford | Currently accepting referrals |
| Sussex | Sussex-Wide CFS/ME Service | 01444 475 799 |
| Greater Manchester / Salford | Chronic Fatigue Service, Salford Royal | 0161 206 5588 |
| Yorkshire | Yorkshire Fatigue Clinic, York | Via GP/NHS referral |
| Norfolk | Norfolk and Waveney ME/CFS Service | Via GP referral |
| Wales | BCUHB ME/CFS Service, Llanfairfechan | Via GP referral |
Generate a referral letter template your GP can use
~/symptom-tracker/referral_letter.js
const {
Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
AlignmentType, BorderStyle, WidthType, ShadingType, VerticalAlign,
HeadingLevel, LevelFormat, PageNumber, Header, Footer
} = require('docx');
const fs = require('fs');
// ─── Palette ───────────────────────────────────────────────────────────────
const TEAL = "1A6E7A";
const TEAL_LIGHT = "D6EEF2";
const GREY_LIGHT = "F5F5F5";
const GREY_MID = "CCCCCC";
const WHITE = "FFFFFF";
const BLACK = "222222";
const MID_GREY = "555555";
// ─── Helpers ───────────────────────────────────────────────────────────────
function thin() { return { style: BorderStyle.SINGLE, size: 4, color: GREY_MID }; }
function none() { return { style: BorderStyle.NONE, size: 0, color: WHITE }; }
function para(text, opts = {}) {
return new Paragraph({
alignment: opts.align || AlignmentType.LEFT,
spacing: { before: opts.before ?? 120, after: opts.after ?? 120 },
children: [new TextRun({
text,
bold: opts.bold ?? false,
italics: opts.italic ?? false,
size: opts.size ?? 22,
color: opts.color ?? BLACK,
font: "Arial",
})]
});
}
function fieldRow(label, placeholder, labelWidth = 2800, inputWidth = 6226) {
return new TableRow({
children: [
new TableCell({
children: [new Paragraph({
spacing: { before: 80, after: 80 },
children: [new TextRun({ text: label, bold: true, size: 20, font: "Arial", color: BLACK })]
})],
width: { size: labelWidth, type: WidthType.DXA },
shading: { fill: GREY_LIGHT, type: ShadingType.CLEAR, color: "auto" },
verticalAlign: VerticalAlign.CENTER,
margins: { top: 80, bottom: 80, left: 140, right: 140 },
borders: { top: thin(), bottom: thin(), left: thin(), right: thin() }
}),
new TableCell({
children: [new Paragraph({
spacing: { before: 80, after: 80 },
children: [new TextRun({ text: placeholder, italics: true, size: 20, font: "Arial", color: "999999" })]
})],
width: { size: inputWidth, type: WidthType.DXA },
shading: { fill: WHITE, type: ShadingType.CLEAR, color: "auto" },
verticalAlign: VerticalAlign.CENTER,
margins: { top: 80, bottom: 80, left: 140, right: 140 },
borders: { top: thin(), bottom: thin(), left: thin(), right: thin() }
})
]
});
}
function sectionHeaderRow(text) {
return new TableRow({
children: [
new TableCell({
columnSpan: 2,
children: [new Paragraph({
spacing: { before: 100, after: 100 },
children: [new TextRun({ text, bold: true, size: 20, color: WHITE, font: "Arial" })]
})],
shading: { fill: TEAL, type: ShadingType.CLEAR, color: "auto" },
margins: { top: 80, bottom: 80, left: 140, right: 140 },
borders: { top: none(), bottom: none(), left: none(), right: none() }
})
]
});
}
function checkRow(label) {
return new TableRow({
children: [
new TableCell({
children: [new Paragraph({
spacing: { before: 60, after: 60 },
children: [
new TextRun({ text: "[ ] ", bold: true, size: 20, font: "Courier New", color: TEAL }),
new TextRun({ text: label, size: 20, font: "Arial", color: BLACK })
]
})],
columnSpan: 2,
shading: { fill: WHITE, type: ShadingType.CLEAR, color: "auto" },
margins: { top: 60, bottom: 60, left: 200, right: 140 },
borders: { top: thin(), bottom: thin(), left: thin(), right: thin() }
})
]
});
}
function noteRow(label, lines = 2) {
// multi-line text box
return new TableRow({
children: [
new TableCell({
children: [new Paragraph({
spacing: { before: 80, after: 80 },
children: [new TextRun({ text: label, bold: true, size: 20, font: "Arial", color: BLACK })]
})],
width: { size: 2800, type: WidthType.DXA },
shading: { fill: GREY_LIGHT, type: ShadingType.CLEAR, color: "auto" },
verticalAlign: VerticalAlign.TOP,
margins: { top: 80, bottom: 80, left: 140, right: 140 },
borders: { top: thin(), bottom: thin(), left: thin(), right: thin() }
}),
new TableCell({
children: Array.from({ length: lines }, () => new Paragraph({
spacing: { before: 100, after: 100 },
children: [new TextRun({ text: "", size: 20, font: "Arial" })]
})),
width: { size: 6226, type: WidthType.DXA },
shading: { fill: WHITE, type: ShadingType.CLEAR, color: "auto" },
margins: { top: 80, bottom: 80, left: 140, right: 140 },
borders: { top: thin(), bottom: thin(), left: thin(), right: thin() }
})
]
});
}
// ─── Build letter body ──────────────────────────────────────────────────────
// SECTION A: GP / Practice details
const sectionA = new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
rows: [
sectionHeaderRow("A. REFERRING PRACTICE"),
fieldRow("Practice name", "[Practice name]"),
fieldRow("GP name", "Dr [First name] [Surname]"),
fieldRow("Address", "[Street, Town, County, Postcode]"),
fieldRow("Phone", "[01xxx xxxxxx]"),
fieldRow("Email", "[gp@nhs.net]"),
fieldRow("Date of letter", "[DD/MM/YYYY]"),
]
});
// SECTION B: Patient details
const sectionB = new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
rows: [
sectionHeaderRow("B. PATIENT DETAILS"),
fieldRow("Full name", "[Patient full name]"),
fieldRow("Date of birth", "[DD/MM/YYYY]"),
fieldRow("NHS number", "[NHS number]"),
fieldRow("Address", "[Patient address]"),
fieldRow("Phone", "[Patient phone number]"),
fieldRow("Gender", "[Male / Female / Non-binary / Prefer not to say]"),
]
});
// SECTION C: Referral destination
const sectionC = new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
rows: [
sectionHeaderRow("C. REFERRAL DESTINATION"),
fieldRow("Service / clinic name", "[e.g. Royal London Hospital for Integrated Medicine ME/CFS Service]"),
fieldRow("Address", "[Service address]"),
fieldRow("Referral sent via", "[NHS e-Referral (Choose and Book) / Post / Email]"),
fieldRow("Priority", "Routine [ ] Urgent [ ]"),
]
});
// SECTION D: Clinical summary
const sectionD = new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
rows: [
sectionHeaderRow("D. CLINICAL SUMMARY"),
fieldRow("Duration of symptoms", "[e.g. 12 months]"),
fieldRow("Onset", "[Gradual / Sudden / Post-viral / Post-COVID]"),
noteRow("Presenting symptoms", 4),
fieldRow("Functional impact", "[e.g. unable to work / housebound / reduced activity]"),
fieldRow("Prior diagnoses ruled out", "[e.g. hypothyroidism, anaemia, diabetes - all excluded]"),
]
});
// SECTION E: Investigations
const sectionE = new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
rows: [
sectionHeaderRow("E. INVESTIGATIONS COMPLETED (tick all done - attach results)"),
checkRow("Full Blood Count (FBC)"),
checkRow("Thyroid function (TSH, Free T4)"),
checkRow("Ferritin / iron studies"),
checkRow("Vitamin B12 and folate"),
checkRow("Vitamin D (25-OH)"),
checkRow("Fasting glucose / HbA1c"),
checkRow("Renal function (U&E, eGFR)"),
checkRow("Liver function tests (LFTs)"),
checkRow("C-reactive protein (CRP) / ESR"),
checkRow("Urinalysis"),
checkRow("Blood pressure and orthostatic vitals"),
new TableRow({
children: [
new TableCell({
columnSpan: 2,
children: [new Paragraph({
spacing: { before: 60, after: 60 },
children: [
new TextRun({ text: "Result summary: ", bold: true, size: 20, font: "Arial", color: BLACK }),
new TextRun({ text: "All within normal limits [ ] Abnormalities noted below [ ]", size: 20, font: "Arial", color: BLACK }),
]
})],
shading: { fill: GREY_LIGHT, type: ShadingType.CLEAR, color: "auto" },
margins: { top: 80, bottom: 80, left: 200, right: 140 },
borders: { top: thin(), bottom: thin(), left: thin(), right: thin() }
})
]
}),
noteRow("Abnormalities / notes", 2),
]
});
// SECTION F: ME/CFS criteria check
const sectionF = new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
rows: [
sectionHeaderRow("F. IOM / NICE 2021 ME/CFS CRITERIA CHECK (tick if present)"),
checkRow("Substantial reduction in activity lasting >6 months with new, unexplained fatigue"),
checkRow("Post-Exertional Malaise (PEM) - symptoms worsen after physical or mental effort"),
checkRow("Unrefreshing sleep"),
checkRow("Cognitive impairment (brain fog, difficulty concentrating, memory problems)"),
checkRow("Orthostatic intolerance (symptoms worsen upright, improve lying down)"),
new TableRow({
children: [
new TableCell({
columnSpan: 2,
children: [new Paragraph({
spacing: { before: 80, after: 80 },
children: [new TextRun({
text: "Note: NICE 2021 guideline requires symptoms 1-3 plus at least one of 4 or 5, present at least half the time with moderate, substantial, or severe intensity.",
italics: true, size: 18, font: "Arial", color: MID_GREY
})]
})],
shading: { fill: TEAL_LIGHT, type: ShadingType.CLEAR, color: "auto" },
margins: { top: 80, bottom: 80, left: 200, right: 140 },
borders: { top: thin(), bottom: thin(), left: thin(), right: thin() }
})
]
}),
]
});
// SECTION G: Current management
const sectionG = new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
rows: [
sectionHeaderRow("G. CURRENT MANAGEMENT"),
noteRow("Current medications", 2),
noteRow("Supplements", 1),
noteRow("Other referrals / services", 2),
noteRow("What has been tried so far", 2),
]
});
// SECTION H: Free text / reason for referral
const sectionH = new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
rows: [
sectionHeaderRow("H. REASON FOR REFERRAL (free text)"),
new TableRow({
children: [
new TableCell({
columnSpan: 2,
children: Array.from({ length: 8 }, () =>
new Paragraph({ spacing: { before: 100, after: 100 }, children: [new TextRun({ text: "", size: 20 })] })
),
shading: { fill: WHITE, type: ShadingType.CLEAR, color: "auto" },
margins: { top: 100, bottom: 100, left: 200, right: 200 },
borders: { top: thin(), bottom: thin(), left: thin(), right: thin() }
})
]
}),
new TableRow({
children: [
new TableCell({
columnSpan: 2,
children: [new Paragraph({
spacing: { before: 80, after: 80 },
children: [new TextRun({
text: "Suggested opening: \"I am referring [patient name], a [age]-year-old [gender], who presents with a [duration]-history of persistent, debilitating fatigue, cognitive impairment and unrefreshing sleep, for which no alternative medical explanation has been found following thorough investigation. The presentation is consistent with ME/CFS under NICE 2021 criteria. I am requesting specialist assessment, diagnosis confirmation, and guidance on management.\"",
italics: true, size: 18, font: "Arial", color: MID_GREY
})]
})],
shading: { fill: TEAL_LIGHT, type: ShadingType.CLEAR, color: "auto" },
margins: { top: 80, bottom: 80, left: 200, right: 140 },
borders: { top: thin(), bottom: thin(), left: thin(), right: thin() }
})
]
}),
]
});
// SECTION I: GP signature
const sectionI = new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
rows: [
sectionHeaderRow("I. SIGNATURE"),
fieldRow("GP signature", "[Signature]"),
fieldRow("Printed name", "[Dr First name Surname]"),
fieldRow("GMC number", "[GMC number]"),
fieldRow("Date", "[DD/MM/YYYY]"),
]
});
// ─── Assemble ───────────────────────────────────────────────────────────────
const doc = new Document({
styles: {
default: {
document: { run: { font: "Arial", size: 22, color: BLACK } }
}
},
sections: [{
properties: {},
headers: {
default: new Header({
children: [
new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
rows: [
new TableRow({
children: [
new TableCell({
children: [
new Paragraph({
spacing: { before: 60, after: 20 },
children: [new TextRun({ text: "NHS GP REFERRAL LETTER", bold: true, size: 28, color: TEAL, font: "Arial" })]
}),
new Paragraph({
spacing: { before: 0, after: 60 },
children: [new TextRun({ text: "Myalgic Encephalomyelitis / Chronic Fatigue Syndrome (ME/CFS) Specialist Service", size: 18, color: MID_GREY, font: "Arial", italics: true })]
}),
],
borders: { top: none(), bottom: { style: BorderStyle.SINGLE, size: 8, color: TEAL }, left: none(), right: none() },
margins: { bottom: 80 }
})
]
})
]
})
]
})
},
footers: {
default: new Footer({
children: [
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { before: 40, after: 0 },
children: [new TextRun({
text: "ME/CFS Referral Template | Based on NICE guideline NG206 (2021) & NICE CKS (May 2025) | Page ",
size: 16, color: "999999", font: "Arial"
}),
new TextRun({ children: [PageNumber.CURRENT], size: 16, color: "999999", font: "Arial" }),
new TextRun({ text: " of ", size: 16, color: "999999", font: "Arial" }),
new TextRun({ children: [PageNumber.TOTAL_PAGES], size: 16, color: "999999", font: "Arial" })
]
})
]
})
},
children: [
// Intro note
new Paragraph({
spacing: { before: 200, after: 60 },
children: [new TextRun({ text: "INSTRUCTIONS FOR GP", bold: true, size: 22, color: TEAL, font: "Arial" })]
}),
new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
rows: [
new TableRow({
children: [
new TableCell({
columnSpan: 1,
children: [
new Paragraph({ spacing: { before: 80, after: 60 }, children: [new TextRun({ text: "This template is provided by the patient to assist with referral preparation. The GP should:", size: 20, font: "Arial", color: BLACK })] }),
...[
"Complete all sections A-I, deleting placeholder text in [brackets]",
"Attach copies of all relevant blood test results",
"Reference NICE guideline NG206 (2021) and the May 2025 NICE Clinical Knowledge Summary on ME/CFS",
"Send via NHS e-Referral (Choose and Book) where available, or directly to the clinic",
"Inform the patient of the referral and expected waiting time",
].map(item => new Paragraph({
spacing: { before: 40, after: 40 },
children: [
new TextRun({ text: " - ", size: 20, font: "Arial", color: TEAL, bold: true }),
new TextRun({ text: item, size: 20, font: "Arial", color: BLACK })
]
})),
new Paragraph({ spacing: { before: 80, after: 80 }, children: [new TextRun({ text: "Under the NHS Constitution, the patient has the right to be referred to a clinic of their choosing.", italics: true, size: 18, font: "Arial", color: MID_GREY })] }),
],
shading: { fill: TEAL_LIGHT, type: ShadingType.CLEAR, color: "auto" },
margins: { top: 100, bottom: 100, left: 180, right: 180 },
borders: { top: thin(), bottom: thin(), left: { style: BorderStyle.SINGLE, size: 16, color: TEAL }, right: thin() }
})
]
})
]
}),
new Paragraph({ spacing: { before: 280, after: 100 }, children: [new TextRun("")] }),
sectionA,
new Paragraph({ spacing: { before: 200, after: 0 }, children: [new TextRun("")] }),
sectionB,
new Paragraph({ spacing: { before: 200, after: 0 }, children: [new TextRun("")] }),
sectionC,
new Paragraph({ spacing: { before: 200, after: 0 }, children: [new TextRun("")] }),
sectionD,
new Paragraph({ spacing: { before: 200, after: 0 }, children: [new TextRun("")] }),
sectionE,
new Paragraph({ spacing: { before: 200, after: 0 }, children: [new TextRun("")] }),
sectionF,
new Paragraph({ spacing: { before: 200, after: 0 }, children: [new TextRun("")] }),
sectionG,
new Paragraph({ spacing: { before: 200, after: 0 }, children: [new TextRun("")] }),
sectionH,
new Paragraph({ spacing: { before: 200, after: 0 }, children: [new TextRun("")] }),
sectionI,
new Paragraph({ spacing: { before: 300, after: 0 }, children: [new TextRun("")] }),
]
}]
});
Packer.toBuffer(doc).then(buffer => {
fs.writeFileSync("/home/daytona/workspace/symptom-tracker/ME_CFS_Referral_Letter_Template.docx", buffer);
console.log("Done.");
});
cd /home/daytona/workspace/symptom-tracker && node referral_letter.js 2>&1
python3 -c " import zipfile with zipfile.ZipFile('/home/daytona/workspace/symptom-tracker/ME_CFS_Referral_Letter_Template.docx') as z: xml = z.read('word/document.xml').decode('utf-8', errors='replace') print('Valid. Size:', len(xml), 'chars') # Check key sections are present checks = ['REFERRING PRACTICE', 'PATIENT DETAILS', 'CLINICAL SUMMARY', 'IOM / NICE', 'REASON FOR REFERRAL', 'SIGNATURE'] for c in checks: print(c + ':', 'FOUND' if c in xml else 'MISSING') "
ME CFS Referral Letter Template
Word Document · DOCX
| Section | Contents |
|---|---|
| A. Referring Practice | GP name, practice address, phone, email, date |
| B. Patient Details | Name, DOB, NHS number, address |
| C. Referral Destination | Clinic name, address, send method, priority |
| D. Clinical Summary | Duration, onset, symptoms, functional impact, diagnoses excluded |
| E. Investigations Checklist | 11 tickboxes (FBC, thyroid, ferritin, B12, Vit D, HbA1c, etc.) with space to note any abnormalities |
| F. NICE 2021 Criteria Check | 5 tickboxes for the IOM/NICE ME/CFS diagnostic criteria - confirms the referral is clinically justified |
| G. Current Management | Medications, supplements, what has already been tried |
| H. Reason for Referral | Free-text box + a suggested pre-written opening paragraph your GP can use or adapt |
| I. Signature | GP signature, printed name, GMC number, date |