Skip to content
Learn Agentic AI16 min read0 views

AI Agent for Special Education: IEP Tracking, Accommodation Management, and Parent Updates

Build an AI agent that tracks Individualized Education Program goals, manages accommodation compliance, generates progress reports, and coordinates the special education team.

The Special Education Coordination Challenge

Special education is one of the most documentation-intensive areas of education. Each student with an Individualized Education Program (IEP) has specific goals, accommodations, service minutes, and progress benchmarks that must be tracked, reported, and coordinated across a team of teachers, specialists, and parents. Missing a compliance deadline or failing to implement an accommodation can have legal consequences. An AI agent can track these obligations systematically and ensure nothing falls through the cracks.

IEP Data Model

The IEP data model must capture goals, accommodations, service delivery, and team membership with precision.

from dataclasses import dataclass, field
from enum import Enum
from datetime import date, datetime
from typing import Optional


class GoalStatus(Enum):
    NOT_STARTED = "not_started"
    IN_PROGRESS = "in_progress"
    MEETING_BENCHMARK = "meeting_benchmark"
    MASTERED = "mastered"
    NOT_MAKING_PROGRESS = "not_making_progress"
    MODIFIED = "modified"


class AccommodationType(Enum):
    TESTING = "testing"
    CLASSROOM = "classroom"
    BEHAVIORAL = "behavioral"
    PHYSICAL = "physical"
    TECHNOLOGY = "technology"
    COMMUNICATION = "communication"


class ServiceType(Enum):
    SPEECH_THERAPY = "speech_therapy"
    OCCUPATIONAL_THERAPY = "occupational_therapy"
    PHYSICAL_THERAPY = "physical_therapy"
    COUNSELING = "counseling"
    BEHAVIOR_SUPPORT = "behavior_support"
    READING_SPECIALIST = "reading_specialist"
    RESOURCE_ROOM = "resource_room"


class ComplianceStatus(Enum):
    COMPLIANT = "compliant"
    AT_RISK = "at_risk"
    NON_COMPLIANT = "non_compliant"


@dataclass
class IEPGoal:
    goal_id: str
    area: str  # reading, math, behavior, social, motor
    description: str
    baseline: str
    target: str
    measurement_method: str
    status: GoalStatus = GoalStatus.NOT_STARTED
    progress_notes: list[dict] = field(default_factory=list)
    target_date: Optional[date] = None


@dataclass
class Accommodation:
    accommodation_id: str
    description: str
    accommodation_type: AccommodationType
    applies_to: list[str] = field(default_factory=list)
    implementation_notes: str = ""
    is_active: bool = True


@dataclass
class ServiceDelivery:
    service_type: ServiceType
    provider_name: str
    minutes_per_week: int
    location: str  # general ed, resource room, therapy room
    actual_minutes_delivered: list[dict] = field(
        default_factory=list
    )


@dataclass
class IEP:
    student_id: str
    student_name: str
    grade_level: int
    disability_category: str
    case_manager: str
    start_date: date
    annual_review_date: date
    triennial_review_date: date
    goals: list[IEPGoal] = field(default_factory=list)
    accommodations: list[Accommodation] = field(default_factory=list)
    services: list[ServiceDelivery] = field(default_factory=list)
    team_members: list[dict] = field(default_factory=list)
    parent_contacts: list[dict] = field(default_factory=list)


@dataclass
class ProgressReport:
    student_id: str
    reporting_period: str
    generated_at: datetime
    goal_updates: list[dict] = field(default_factory=list)
    service_delivery_summary: list[dict] = field(
        default_factory=list
    )
    accommodation_compliance: list[dict] = field(
        default_factory=list
    )
    recommendations: list[str] = field(default_factory=list)

Compliance Monitoring Engine

The compliance engine checks that all required services are being delivered and accommodations are being implemented.

IEPS: dict[str, IEP] = {}


def check_service_compliance(student_id: str) -> list[dict]:
    iep = IEPS.get(student_id)
    if not iep:
        return []

    compliance_issues = []
    for service in iep.services:
        if not service.actual_minutes_delivered:
            compliance_issues.append({
                "service": service.service_type.value,
                "provider": service.provider_name,
                "required_minutes": service.minutes_per_week,
                "delivered_minutes": 0,
                "status": ComplianceStatus.NON_COMPLIANT.value,
                "action": "No service delivery logged this period.",
            })
            continue

        recent_entries = service.actual_minutes_delivered[-4:]
        avg_minutes = sum(
            e.get("minutes", 0) for e in recent_entries
        ) / len(recent_entries)

        if avg_minutes < service.minutes_per_week * 0.8:
            status = ComplianceStatus.NON_COMPLIANT
            action = (
                f"Average {avg_minutes:.0f} min/week vs "
                f"required {service.minutes_per_week}. "
                f"Schedule make-up sessions."
            )
        elif avg_minutes < service.minutes_per_week:
            status = ComplianceStatus.AT_RISK
            action = "Slightly below target. Monitor closely."
        else:
            status = ComplianceStatus.COMPLIANT
            action = "On track."

        compliance_issues.append({
            "service": service.service_type.value,
            "provider": service.provider_name,
            "required_minutes": service.minutes_per_week,
            "avg_delivered_minutes": round(avg_minutes),
            "status": status.value,
            "action": action,
        })

    return compliance_issues


def generate_progress_report(student_id: str) -> dict:
    iep = IEPS.get(student_id)
    if not iep:
        return {"error": "IEP not found"}

    goal_updates = []
    for goal in iep.goals:
        latest_note = (
            goal.progress_notes[-1] if goal.progress_notes else {}
        )
        goal_updates.append({
            "area": goal.area,
            "goal": goal.description,
            "status": goal.status.value,
            "baseline": goal.baseline,
            "target": goal.target,
            "current_performance": latest_note.get(
                "performance", "No data"
            ),
            "on_track": goal.status in (
                GoalStatus.IN_PROGRESS,
                GoalStatus.MEETING_BENCHMARK,
                GoalStatus.MASTERED,
            ),
        })

    service_summary = check_service_compliance(student_id)

    # Check accommodation implementation
    accommodation_status = []
    for acc in iep.accommodations:
        if acc.is_active:
            accommodation_status.append({
                "accommodation": acc.description,
                "type": acc.accommodation_type.value,
                "applies_to": acc.applies_to,
            })

    days_to_annual = (iep.annual_review_date - date.today()).days
    recommendations = []
    if days_to_annual <= 60:
        recommendations.append(
            f"Annual IEP review due in {days_to_annual} days. "
            f"Schedule team meeting."
        )
    goals_not_progressing = [
        g for g in iep.goals
        if g.status == GoalStatus.NOT_MAKING_PROGRESS
    ]
    if goals_not_progressing:
        recommendations.append(
            f"{len(goals_not_progressing)} goal(s) not making "
            f"progress. Consider modifying goals or strategies."
        )

    return {
        "student": iep.student_name,
        "grade": iep.grade_level,
        "case_manager": iep.case_manager,
        "goals": goal_updates,
        "services": service_summary,
        "accommodations": accommodation_status,
        "recommendations": recommendations,
        "annual_review_date": iep.annual_review_date.isoformat(),
        "days_to_annual_review": days_to_annual,
    }

Agent Tools and Assembly

from agents import Agent, function_tool, Runner
import json


@function_tool
def get_iep_summary(student_id: str) -> str:
    """Get a summary of a student IEP including goals and services."""
    report = generate_progress_report(student_id)
    return json.dumps(report)


@function_tool
def check_compliance(student_id: str) -> str:
    """Check service delivery compliance for a student."""
    issues = check_service_compliance(student_id)
    return json.dumps(issues) if issues else "No compliance data."


@function_tool
def log_goal_progress(
    student_id: str,
    goal_id: str,
    performance: str,
    notes: str,
) -> str:
    """Log progress toward an IEP goal."""
    iep = IEPS.get(student_id)
    if not iep:
        return "IEP not found."
    for goal in iep.goals:
        if goal.goal_id == goal_id:
            goal.progress_notes.append({
                "date": date.today().isoformat(),
                "performance": performance,
                "notes": notes,
                "logged_by": "agent",
            })
            return json.dumps({
                "status": "Progress logged",
                "goal": goal.description,
                "total_entries": len(goal.progress_notes),
            })
    return "Goal not found."


@function_tool
def get_upcoming_reviews() -> str:
    """Get all IEPs with upcoming annual or triennial reviews."""
    today = date.today()
    upcoming = []
    for student_id, iep in IEPS.items():
        days_annual = (iep.annual_review_date - today).days
        days_triennial = (iep.triennial_review_date - today).days
        if days_annual <= 90 or days_triennial <= 90:
            upcoming.append({
                "student": iep.student_name,
                "student_id": student_id,
                "case_manager": iep.case_manager,
                "annual_review": iep.annual_review_date.isoformat(),
                "days_to_annual": days_annual,
                "triennial_review": (
                    iep.triennial_review_date.isoformat()
                ),
                "days_to_triennial": days_triennial,
            })
    upcoming.sort(key=lambda u: min(
        u["days_to_annual"], u["days_to_triennial"]
    ))
    return json.dumps(upcoming) if upcoming else "No upcoming reviews."


sped_agent = Agent(
    name="Special Education Coordinator",
    instructions="""You are a special education coordination agent.
    Help case managers track IEP goals, monitor service delivery
    compliance, log progress data, and prepare for reviews. Be
    precise with compliance data — this has legal implications.
    When service minutes are below required levels, flag it
    immediately with specific remediation steps. Never make
    clinical or diagnostic judgments. Always recommend involving
    the full IEP team for significant changes.""",
    tools=[
        get_iep_summary,
        check_compliance,
        log_goal_progress,
        get_upcoming_reviews,
    ],
)

Compliance Dashboard Pattern

For case managers overseeing multiple students, a dashboard view is essential.

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

def generate_caseload_dashboard(case_manager: str) -> dict:
    students = [
        iep for iep in IEPS.values()
        if iep.case_manager == case_manager
    ]

    dashboard = {
        "case_manager": case_manager,
        "total_students": len(students),
        "compliance_summary": {
            "compliant": 0,
            "at_risk": 0,
            "non_compliant": 0,
        },
        "upcoming_reviews": [],
        "goals_needing_attention": [],
    }

    today = date.today()
    for iep in students:
        # Service compliance
        issues = check_service_compliance(iep.student_id)
        for issue in issues:
            status = issue["status"]
            if status in dashboard["compliance_summary"]:
                dashboard["compliance_summary"][status] += 1

        # Upcoming reviews
        days_to_review = (iep.annual_review_date - today).days
        if days_to_review <= 60:
            dashboard["upcoming_reviews"].append({
                "student": iep.student_name,
                "review_date": iep.annual_review_date.isoformat(),
                "days_remaining": days_to_review,
            })

        # Goals needing attention
        for goal in iep.goals:
            if goal.status == GoalStatus.NOT_MAKING_PROGRESS:
                dashboard["goals_needing_attention"].append({
                    "student": iep.student_name,
                    "goal_area": goal.area,
                    "goal": goal.description[:80],
                })

    return dashboard

FAQ

How does the agent ensure IDEA compliance for service delivery tracking?

The agent tracks actual minutes delivered against the IEP-mandated minutes for each service type. When delivery falls below 80% of the required amount, it flags the case as non-compliant and recommends make-up sessions. All service delivery data is timestamped and attributed to the provider for audit purposes. The system generates the documentation trail required by IDEA regulations.

Can the agent help prepare for IEP meetings?

Yes. Before an annual review, the agent compiles a comprehensive report including goal progress data across all reporting periods, service delivery compliance percentages, accommodation implementation status, and data-driven recommendations for goal modification. This report gives the IEP team concrete data to inform decisions rather than relying on subjective impressions.

How does the agent handle confidentiality of special education records?

Special education records are protected under FERPA and IDEA with even stricter requirements than general education records. The agent enforces role-based access — only IEP team members listed in the student record can access data. All queries are logged with the requesting user identity and timestamp. The agent never includes student names in error messages or logs, using only student IDs for system-level operations.


#AIAgents #EdTech #SpecialEducation #Python #IEPManagement #AgenticAI #LearnAI #AIEngineering

Share this article
C

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.