Stable aliases
A-7K3F9Q instead of a name, an email or an id: the same person always gets the same alias, computed with a key that never leaves the machine.
Resolvable by the right person
An encrypted local directory remembers who each alias is. The person running your program asks pseudonym whois in their own terminal, offline.
One alias per service
The same student is one alias in the LMS and another in the mail, so a model can't join what it learns about them. Linking services is opt-in.
Free text too
redact() replaces the directory's people in a submission or a post with their aliases, and emails, cards, IBANs and national ids of nine countries with placeholders.
Inside your program
A library, not a server: no MCP tool an agent could call to undo it, no runtime dependencies, nothing sent anywhere.
Honest about its limits
Pseudonymization, not anonymization. The documentation says what it doesn't catch and how to keep an agent away from the key.
Three calls
import { remember, resolve, redact } from "@falkenslab/pseudonym";
const service = "moodle@campus.example.org";
// Before a result reaches the model: people become aliases.
const alias = await remember({
service,
identifiers: { email: user.email, serviceUserId: String(user.id) },
displayName: user.fullname,
}); // "A-7K3F9Q"
// A write tool gets an alias back from the model.
const userId = await resolve("A-7K3F9Q", { service });
// Text people wrote.
const { text } = await redact(post.message, { service });
See it working
The classroom MCP example is a small MCP server over a made-up course: the model lists students, reads the forum and grades someone, and only ever sees aliases.
The person in charge keeps the key and the directory, and answers pseudonym whois A-7K3F9Q in their terminal. See the CLI.