Education
Learning platforms, school districts, and ed-tech startups adding AI tutors, homework help, or curriculum-authoring assistants on top of @pleach/recipes/education.
The education use case covers K-12 districts, university research groups, ed-tech startups, and learning-platform vendors building AI tutors, homework help, study-skill coaches, or curriculum-authoring assistants. Budget owner is usually a product or curriculum director, not a CTO. Procurement gates the buy on three things: identifier redaction (so a teacher pasting a transcript doesn't leak student PII into the LLM), a hard per-session spend cap (so a runaway loop in a classroom can't burn the district's quota), and per-district tenancy (so District A's data and spend can't cross into District B).
This page is the landing for the education use case. The three sub-pages go deeper:
- Student safety —
the shipped redaction patterns plus the composable
KeyedRegexScrubbershape for district-specific extensions. - FERPA / COPPA scope — what the current compliance posture covers and what it doesn't. Read this before signing a procurement form.
- Per-district tenant + cost-cap — multi-tenant composition and how cost ceilings actually get enforced at the gateway boundary.
Who this is for
- A district-internal team standing up an AI homework helper for one or more schools, gated by a per-student or per-session spend ceiling.
- An ed-tech vendor adding a tutoring assistant to an existing LMS or curriculum product, where the contractual customer is the district and the data subject is the student.
- A university research group running pedagogical-replay studies where every chat session is captured for semester-over-semester comparison.
- A learning-platform startup whose buyer expects a FERPA / COPPA conversation during the sales cycle and needs a concrete answer to "what do you redact before the model sees it?"
Quickstart
npm install @pleach/recipes @pleach/complianceimport { educationAgent } from "@pleach/recipes/education";
const bot = educationAgent({
districtId: "district-1234",
complianceProfile: "ferpa+coppa",
contentSafety: ["self-harm", "profanity"],
costCapUsdPerSession: 0.25,
});
const reply = await bot.ask(
"Hi Mrs. Johnson — Student ID 9876543 needs help with fractions",
);
// LLM sees: "Hi Mrs. Johnson — [STUDENT] needs help with fractions"That five-line config wires three pieces of substrate that ship today:
- The student-safety scrubber from
@pleach/compliance/education(see Student safety). Runs beforeask()forwards to the model, so the LLM-bound copy is redacted regardless of where you later persist the transcript. - A per-session cost-cap policy keyed at the configured
ceiling. The policy is registered on the runtime so consumers
can drive
canSpend()/recordSpend()from their per-turn gate, and the same shape is used by the gateway-side enforcer (see Per-district tenant + cost-cap). - A compliance profile plugin that maps the FERPA / COPPA
labels to the closest shipped analog (currently
gdpr— data-minimization plus identifier redaction). The substitution is surfaced on the runtime tag and awarn-oncenotice fires to your console.
What you get
- Identifier redaction (student ID patterns, grade bands, school-issued email domains, labeled parent contact lines) applied to the user message before the runtime sees it.
- A per-session cost ceiling exposed on the runtime via the
EDUCATION_RUNTIME_TAGsymbol — drive the policy from your turn-gate to fail closed when a classroom session blows the ceiling. - A
districtIdtag on the runtime that downstream code (audit ledger, gateway cost aggregator, your billing pipeline) can read to scope every write to one district. - A drop-in compatible
Chatbotshape (ask/newSession/reset/runtime) — same surface assimpleChatbot.
Honest scope-limits
These belong on the procurement page. Don't surprise a district counsel with them three weeks into a pilot.
- There is no
ferpa-coppaprofile literal in@pleach/compliancetoday. The shippedComplianceProfileunion is"hipaa" | "gdpr" | "pci-dss" | "soc2".educationAgentaccepts the education-facing strings (ferpa,coppa,ferpa+coppa) and substitutesgdpras the closest shipped analog. The substitution is recorded on the runtime tag (requestedProfile+mappedProfile) so your audit ledger can show what was asked for and what was actually applied. This is NOT full FERPA / COPPA adequacy — see FERPA / COPPA scope for the gap list. - The cost-cap is registered for telemetry; the gateway is
the enforcement point. The policy is exposed on the runtime
tag so callers can use the same shape as the gateway-side
ceiling, but
educationAgent.ask()does not consult the policy before invoking the model — there is no substrate hook today for the recipe to observe per-turn USD spend. WireCostCeilingMiddlewarefrom@pleach/gateway/swarmat the routing boundary if you need hard cutoff. See Per-district tenant + cost-cap. - Pedagogical replay is recorded on the tag only.
Byte-identical replay requires greenfield runtime work not yet
shipped. The
pedagogicalReplayfield is accepted for forward-compat but does not change runtime behavior today. - The shipped student-safety scrubber redacts identifiers,
not content categories. When you pass
contentSafety: ["self-harm", "profanity"], the categories are surfaced on the runtime tag for your telemetry, but the shipped scrubber currently redacts student-identifying fragments (IDs, grade bands, school-issued emails, labeled parent contact lines). Per-category content moderation is tracked but not shipped — wire a separate moderation API (Anthropic / OpenAI moderation endpoints, or your own classifier) for category-level enforcement.
Config reference
type EducationContentSafetyCategory =
| "self-harm"
| "age-inappropriate"
| "profanity"
| "off-curriculum";
type EducationComplianceProfile = "ferpa" | "coppa" | "ferpa+coppa";
interface EducationAgentConfig extends SimpleChatbotConfig {
/** Stable district / institutional tenant id. Required. */
districtId: string;
/** Pseudonymous per-student attribution id. Optional. */
studentId?: string;
/** FERPA / COPPA profile. Maps to `gdpr` bundle today. */
complianceProfile?: EducationComplianceProfile;
/** Recorded on the runtime tag. */
contentSafety?: readonly EducationContentSafetyCategory[];
/** Recorded only; gateway is the enforcement point. */
perDistrictMonthlyBudgetUsd?: number;
/** Recorded only; greenfield runtime required. */
pedagogicalReplay?: { enabled: boolean };
/** Default 0.50. Drives the in-memory cost-cap ceiling. */
costCapUsdPerSession?: number;
/** Default true. Pass false to skip student-safety scrubbing. */
studentSafetyEnabled?: boolean;
}The runtime tag is symbol-keyed so cross-bundle consumers (the
symbol obtained via require("@pleach/recipes") vs
require("@pleach/recipes/education") in different consumer
bundles) resolve to the same identity:
import { EDUCATION_RUNTIME_TAG } from "@pleach/recipes/education";
const tag = (bot.runtime as unknown as Record<symbol, any>)[
EDUCATION_RUNTIME_TAG
];
// tag.districtId : string
// tag.studentId? : string
// tag.requestedProfile : "ferpa" | "coppa" | "ferpa+coppa" | null
// tag.mappedProfile : "gdpr" | null
// tag.contentSafety : readonly EducationContentSafetyCategory[]
// tag.costCap : CostCapPolicy
// tag.costCapCeilingUsd : number
// tag.studentSafetyEnabled: booleanSource
The factory body lives at
packages/recipes/src/education.ts. The education-facet helpers it
composes live at packages/compliance/src/education/studentSafety.ts.
The per-root-turn cost cap referenced by
Per-district tenant + cost-cap
lives at packages/core/src/spawn/rootTurnCostCap.ts.
See also
- Student safety
- FERPA / COPPA scope
- Per-district tenant + cost-cap
@pleach/recipesoverviewcompliantChatbot— the sibling recipe for HIPAA / GDPR / PCI-DSS / SOC 2.