← Projects

M365 Reports

live

AI-narrated PDF reports from Microsoft 365 data

for
My clients. Client work, so they aren't named.
started
3 May 2026 as one engine. The reports themselves are older.
in
A client's Microsoft 365 audit log and SharePoint lists
out
A branded PDF. I read every page before it goes to the client.

One engine behind the branded PDF reports my clients get. It pulls data out of their Microsoft 365 tenant over Graph, works out the numbers, has Claude write the findings up, and renders a PDF in the client’s own brand.

  • Departure audits. When someone resigns, 90 days of their SharePoint, OneDrive and Exchange activity, checked against a list of red flags and written up as a risk assessment. What happened when one said HIGH.
  • Monthly enrolment reports for a childcare group: enquiries, tours and enrolments per centre, stale leads, and how fast each centre first responds, read out of SharePoint’s version history. How that works, and what it misses.

The same data also answered bigger questions: 22 months of enquiries turned up a finding that halved once it was split by centre.

Nothing goes to a client until I’ve read every page. These are internal tools, so there’s no public link, and the clients aren’t named.

Stack

Microsoft Graph
Pulls the audit log and the SharePoint lists out of the client's tenant, including each list item's version history.
Python
Works out every number and checks the red flags before the model writes a word.
Claude
Writes the summary and the findings from those numbers.
ReportLab
Lays out the PDF in the client's own brand.
FastAPI
A small service that starts a report on request and hands back the PDF.

Build log

  1. Two departure audits. One scored HIGH. Twenty minutes in the raw rows made it MEDIUM, and turned up six sentences the template printed whatever the data said. All six fixed.  Read →

  2. Found every font weight had been rendering as the same one, so no report had real bold. Fixed.

  3. Exported the whole enquiry list, 22 months of it, to ask what a monthly report can't. My favourite finding about halved once it was split by centre.  Read →

  4. The May enrolment report led with a group median first response of 0.1 days. The busiest centre's was four days. Not fixed yet.  Read →

  5. Rebuilt as one engine. The separate report scripts moved into one repo with a shared PDF core.

Writing