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.
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.
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.
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.