# Education (/docs/use-cases/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](/docs/use-cases/education/student-safety) —
  the shipped redaction patterns plus the composable
  `KeyedRegexScrubber` shape for district-specific extensions.
* [FERPA / COPPA scope](/docs/use-cases/education/ferpa-coppa) —
  what the current compliance posture covers and what it doesn't.
  Read this before signing a procurement form.
* [Per-district tenant + cost-cap](/docs/use-cases/education/per-district-tenant) —
  multi-tenant composition and how cost ceilings actually get
  enforced at the gateway boundary.

## Who this is for [#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 [#quickstart]

```bash
npm install @pleach/recipes @pleach/compliance
```

```ts
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](/docs/use-cases/education/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](/docs/use-cases/education/per-district-tenant)).
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 [#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`](/docs/recipes/simple-chatbot).

## Honest scope-limits [#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`](/docs/compliance) 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](/docs/use-cases/education/ferpa-coppa)
   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`](/docs/gateway) at the routing
   boundary if you need hard cutoff. See
   [Per-district tenant + cost-cap](/docs/use-cases/education/per-district-tenant).
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 [#config-reference]

```ts
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:

```ts
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 [#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](/docs/use-cases/education/per-district-tenant)
lives at `packages/core/src/spawn/rootTurnCostCap.ts`.

## See also [#see-also]

* [Student safety](/docs/use-cases/education/student-safety)
* [FERPA / COPPA scope](/docs/use-cases/education/ferpa-coppa)
* [Per-district tenant + cost-cap](/docs/use-cases/education/per-district-tenant)
* [`@pleach/recipes` overview](/docs/recipes-pleach-recipes)
* [`compliantChatbot`](/docs/recipes/compliant-chatbot) — the
  sibling recipe for HIPAA / GDPR / PCI-DSS / SOC 2.
