← All work Case study · Two-pass LLM pipeline · Local models

SSW Helper: compliant documentation from a social worker's shorthand

A macOS app that turns quick session notes into Connecticut special-education (CT SEDS) service-log narratives. It runs entirely on local models, with guards against the specific ways models fail at this task.

Audience
School social workers
Platform
macOS · SwiftUI
AI
Apple Foundation Models or Gemma (local)
Status
In use · 50 unit tests
Pass 1: which of 10 service areas apply? NONE is allowed. Pass 2: draft the narrative. Invalid output gets one corrective retry.
The shape of the pipeline. No student information is stored or displayed on this page.

The problem

School social workers must log every service session in the state's special-education system, using a specific structure tied to IEP/504 goals. It's slow, repetitive writing, and the notes involve some of the most sensitive student information a district holds. Cloud AI was not an option.

The pipeline

I split the task into two model calls, so each step is small enough to check:

  1. Classify: choose which of 10 fixed CT SEDS service areas the session covered. The model may answer NONE.
  2. Draft: write the narrative using only the selected areas, following required phrasing rules.

Compliance rules are written into the system prompt as constraints:

System prompt excerpt
"Refer to the child only as 'the student'. Never repeat a student name from the notes."

Push-in sessions also require an exact opening sentence, and the output is checked for it.

Failure-mode guards

Each guard targets a failure I actually observed:

  • Option echo: small models sometimes "classify" by listing all ten options. Those replies are detected and thrown out.
  • Forced choice: allowing NONE stops the model from inventing an area just to answer.
  • Schema check + one corrective retry: invalid output gets one retry with specific corrective instructions; if that also fails, the partial draft is kept instead of losing the work.
  • Model selection by name, so an embedding model can't be loaded by accident

How I verified it

  • 50 XCTest cases covering prompt building, area selection, service-log rules, both backends and the clipboard
  • Compared Apple Intelligence (~3s) with local Gemma (~15s) on output quality and shipped both behind one interface so the user can choose
  • Privacy: notes are never written to disk, and copied text doesn't sync to other devices
  • Iterated with a written handoff.md that records each design decision for the AI agents building it

What this shows for AI training roles

  • Naming a model's failure modes precisely and designing a check for each
  • Breaking a task into steps that can each be checked
  • Comparing models on speed and quality for a specific domain
  • Turning regulatory requirements into prompt constraints