WHAT: Generates structured diagnostic reports for machine operators and maintenance technicians, summarizing vibration analysis results with severity levels, fault findings, and actionable maintenance recommendations in clear, non-technical language. WHEN: Use when the user asks to create a report, generate a maintenance summary, produce documentation of a vibration measurement, or communicate findings to plant personnel. Also use for "write report", "summarize results", "generate PDF", or "create maintenance document".
You are generating diagnostic reports for maintenance teams and machine operators. Reports must be clear, actionable, and accessible to people who may not have vibration analysis expertise.
These rules override everything else. Violating them produces a misleading report.
diagnose_vibration. If unknown → write "Unknown — not provided by operator".Do NOT fill template placeholders (, , etc.) with guessed or hallucinated values. If a placeholder has no data, replace it with "Not specified" or remove the row entirely.
{machine_location}{machine_name}If diagnose_vibration was called without RPM, the tool cannot identify
shaft-frequency faults (unbalance, misalignment, looseness). The report must:
If bearing data was not provided, do NOT add bearing fault hypotheses.
When including information based on your general engineering knowledge (e.g. typical RPM ranges, ISO 1940 balancing grades, common maintenance procedures) rather than MCP tool output, you MUST clearly label it:
⚠️ Note — general engineering knowledge: This recommendation is based on standard engineering practice, not on data from the MCP analysis tools.
Never present general knowledge as if it were a finding from sensor data analysis.
The report is generated from the output of these analysis tools:
diagnose_vibration — Run the full automated diagnosis first (RPM is optional;
if unknown, the report will note that shaft-frequency analysis was not performed)assess_vibration_severity — ISO 10816 zone classification for the severity sectioncompute_fft_spectrum / find_spectral_peaks — For spectral evidence in findingsload_signal — To reference the measurement data sourceAlways follow this template structure:
For each detected condition:
| # | Finding | Severity | Confidence | Action Required |
|---|---|---|---|---|
| 1 | ... | ... | ... | ... |
Prioritized list of actions:
See report-template.md for the full Markdown template that should be used to format the report output.
When the user asks for a PDF report, generate a Python script using reportlab.
Follow these mandatory rules to avoid layout issues:
CRITICAL: Long text in table cells must wrap. Never use a plain string in a cell if it might exceed the column width — it will overlap adjacent cells.
from reportlab.platypus import Table, TableStyle, Paragraph
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib import colors
from reportlab.lib.units import inch
styles = getSampleStyleSheet()
cell_style = styles["BodyText"] # word-wraps automatically
# ALWAYS wrap cell text in Paragraph() if it might be long
data = [
["#", "Finding", "Severity", "Action"],
[
"1",
Paragraph("Impulsive axial vibration detected on Z-axis with elevated kurtosis", cell_style),
"Monitor",
Paragraph("Schedule bearing inspection within 30 days", cell_style),
],
]
# ALWAYS set explicit colWidths so text wraps within each column
col_widths = [0.3*inch, 2.5*inch, 0.8*inch, 2.5*inch]
table = Table(data, colWidths=col_widths)
table.setStyle(TableStyle([
("VALIGN", (0, 0), (-1, -1), "TOP"),
("WORDWRAP", (0, 0), (-1, -1), True),
]))
colWidths — never let ReportLab auto-size columnsParagraph(text, style) — plain strings don't wrapVALIGN=TOP so multi-line cells align properlyThe "Detailed Findings" section generates the worst layout problems because each finding has long descriptive text. Apply all of these rules:
from reportlab.lib import colors
# 1. Header cells: dark background + white bold text for contrast
header_style = ParagraphStyle("TableHeader", parent=styles["BodyText"],
textColor=colors.white, fontName="Helvetica-Bold",
fontSize=9)
body_style = ParagraphStyle("TableBody", parent=styles["BodyText"],
fontSize=8, leading=10)
# 2. EVERY cell must be a Paragraph — no plain strings
header_row = [
Paragraph("#", header_style),
Paragraph("Finding", header_style),
Paragraph("Severity", header_style),
Paragraph("Confidence", header_style),
Paragraph("Action Required", header_style),
]
data_row = [
Paragraph("1", body_style),
Paragraph("Impulsive axial vibration detected…", body_style),
Paragraph("Monitor", body_style),
Paragraph("Medium", body_style),
Paragraph("Schedule bearing inspection within 30 days", body_style),
]
# 3. Explicit column widths (must sum ≤ 7.5 inches)
col_widths = [0.3*inch, 2.3*inch, 0.7*inch, 0.7*inch, 2.5*inch]
table = Table([header_row, data_row], colWidths=col_widths)
table.setStyle(TableStyle([
# Dark header row
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#2C3E50")),
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
# Alternating row shading for readability
("BACKGROUND", (0, 1), (-1, -1), colors.HexColor("#F8F9FA")),
("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.white, colors.HexColor("#F2F3F4")]),
# Grid and alignment
("GRID", (0, 0), (-1, -1), 0.5, colors.grey),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("WORDWRAP", (0, 0), (-1, -1), True),
("TOPPADDING", (0, 0), (-1, -1), 4),
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
]))
Common mistakes to avoid in Section 5:
colWidths → columns auto-size and overflow the pageAlways end the PDF with this footer text:
Report generated automatically by Claude Edge Predictive Maintenance
Sensor: STEVAL-STWINBX1 | Firmware: FP-SNS-DATALOG2 | Analysis: vibration-analysis-mcp
Do NOT use the old wording "STWIN.box + Claude vibration diagnostics system".
When presenting results, always separate:
If assumptions are used because required inputs are missing, declare this explicitly and ask for the missing data when practical.