pleach
Use cases

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 KeyedRegexScrubber shape 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/compliance
import { 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:

  1. The student-safety scrubber from @pleach/compliance/education (see Student safety). Runs before ask() forwards to the model, so the LLM-bound copy is redacted regardless of where you later persist the transcript.
  2. 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).
  3. 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 a warn-once notice 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_TAG symbol — drive the policy from your turn-gate to fail closed when a classroom session blows the ceiling.
  • A districtId tag 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 Chatbot shape (ask / newSession / reset / runtime) — same surface as simpleChatbot.

Honest scope-limits

These belong on the procurement page. Don't surprise a district counsel with them three weeks into a pilot.

  1. There is no ferpa-coppa profile literal in @pleach/compliance today. The shipped ComplianceProfile union is "hipaa" | "gdpr" | "pci-dss" | "soc2". educationAgent accepts the education-facing strings (ferpa, coppa, ferpa+coppa) and substitutes gdpr as 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.
  2. 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. Wire CostCeilingMiddleware from @pleach/gateway/swarm at the routing boundary if you need hard cutoff. See Per-district tenant + cost-cap.
  3. Pedagogical replay is recorded on the tag only. Byte-identical replay requires greenfield runtime work not yet shipped. The pedagogicalReplay field is accepted for forward-compat but does not change runtime behavior today.
  4. 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: boolean

Source

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

On this page