← All courses ← Course home

Lesson 04 of 05

Redact PII on the device

Replace emails, phones, links, and card-shaped numbers with tokens before the model or Private Cloud Compute sees the text.

Agent brief (llms.md)

Redact on the device before respond, before a tool sees a prompt, and before you switch a profile to Private Cloud Compute. Prefer Apple types that already run locally: NSDataDetector for emails, links, and phone numbers. Add your own patterns for account ids you ship.

StoreFull record
RedactorTokens
Model or PCCTokens only
import Foundation

struct PIIRedactor: Sendable {
    func redact(_ text: String, source: TextSource) -> String {
        var output = text
        output = replaceMatches(output, types: [.link, .phoneNumber])
        output = output.replacingOccurrences(
            of: #"\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b"#,
            with: "[email]",
            options: [.regularExpression, .caseInsensitive]
        )
        output = output.replacingOccurrences(
            of: #"\b(?:\d[ -]?){13,19}\b"#,
            with: "[card]",
            options: .regularExpression
        )
        return output
    }

    private func replaceMatches(_ text: String, types: NSTextCheckingResult.CheckingType) -> String {
        guard let detector = try? NSDataDetector(types: types.rawValue) else { return text }
        let range = NSRange(text.startIndex..., in: text)
        var output = text
        for match in detector.matches(in: text, options: [], range: range).reversed() {
            guard let swiftRange = Range(match.range, in: output) else { continue }
            let token = match.resultType == .phoneNumber ? "[phone]" : "[link]"
            output.replaceSubrange(swiftRange, with: token)
        }
        return output
    }
}

Keep a map from token to original value only if a later trusted step must restore it. Store that map in memory or in the app container, not in the session transcript. Never send the map to the model. If you restore a value to show the user, restore it in the UI, not inside respond.

Redactor[email]
SessionSees the token
UIMay restore for display

If a Dynamic Profile moves work to PrivateCloudComputeLanguageModel, run the redactor again on the packet you are about to send. On-device SystemLanguageModel is the safer default for anything that still has residual private text.

Read Run tools in a safe box, Talk to tools with MCP, and Make several agents agree first so a tool cannot read the unredacted file after you already stripped the prompt.

Rule. The transcript should hold tokens, not account numbers.

Next, test the pipeline and keep every check on the device.

Key concepts

  • Detect links, phones, emails, and card shapes, then replace them with tokens.
  • Redact before respond, before tools, and before Private Cloud Compute.
  • The token-to-original map stays outside the session transcript.
  • Restore values in the UI only, not inside respond.

Takeaways

  • The transcript should hold tokens, not account numbers.
  • Never send raw PII to Private Cloud Compute.
  • A tool must not read an unredacted file after you stripped the prompt.