Perplexity Hybrid Compute: How Local PII Routing Redraws the Agent Privacy Boundary
💡 Tool Tip:Regex Tester, AI Token Counter, JSON Formatter
On September 1, 2026, Perplexity shipped hybrid compute to its Mac app: an agent task starts in the cloud and hands sensitive steps down to a model running on your own machine, gated by an open-source 0.6B PII classifier called PII-Tracer. This guide covers the architecture, the published numbers behind the gate (char F1 0.629, recurrence recall 79.4%, long-context recall 0.687 recovering to 0.965 with sliding windows), and where the boundary still leaks.
Cloud first, local for sensitive steps
1. What Shipped, and With Which Models
Hybrid compute is available to Pro, Max, and Enterprise subscribers in the Perplexity Mac app on Apple silicon running macOS 15 or later, with 24 GB of unified memory as the minimum and 32 GB recommended. Local options at launch include Gemma 4 E4B, Qwen3.6 35B-A3B, and a Perplexity post-trained Qwen variant; the setup flow points to a one-click download of PPLX Qwen 3.8 27B. Cloud work still goes to frontier models, and local tokens are not billed and need no API key, because the work never leaves the device. The 24 GB floor is the real constraint: it puts hybrid compute on MacBook Pro, Mac Studio, and Mac Pro tiers rather than base consumer Apple Silicon, which quietly makes the privacy guarantee a hardware question.
from dataclasses import dataclass
@dataclass
class Decision:
outcome: str # local | mask | refuse | ask
model: str
payload: str
def route(step, gate):
verdict = gate.classify(step.text) # 0.6B PII classifier
if not verdict.contains_sensitive:
return Decision("local", "cloud-orchestrator", step.text)
if verdict.pii_types <= {"email", "phone"}:
return Decision("mask", "cloud-orchestrator", gate.mask(step.text))
if verdict.pii_types & {"medical", "financial", "legal"}:
return Decision("local", "pplx-qwen-3.8-27b", step.text)
return Decision("ask", "none", step.text)2. The Router Is the Product
The architectural claim is that an agent can start in the cloud and move to a local model mid-task. That is a routing problem, and routing is where privacy designs usually fail. Perplexity's answer is a cloud orchestrator that owns tool routing and the interface, plus a local gate that decides what may be sent upstream. Four outcomes are defined at the boundary: keep the step local, mask it, refuse it, or ask the user. That vocabulary is more useful than a single boolean. Many real tasks do not need full local execution; they need a redaction pass and then cloud reasoning over the cleaned text. Code sample 1 sketches the same router with explicit outcomes, which is exactly the contract you want written down before you ship an agent over tax returns or medical records.
import httpx
GATE = "http://127.0.0.1:8090/classify" # on-device, no egress
def classify(text: str) -> dict:
r = httpx.post(GATE, json={"text": text}, timeout=5.0)
r.raise_for_status()
return r.json() # {contains_sensitive, pii_types, spans}3. The PII Gate, by the Numbers
Perplexity open-sourced the classifier behind the boundary. PII-Tracer is a 0.6B bidirectional encoder adapted from a Qwen3 backbone; it replaces the causal mask with padding-aware bidirectional attention over a 4,096-token window and emits 37 labels from a linear tagging head: one outside-span label plus BIOES position labels for each of nine PII types, with an auxiliary head predicting whether a conversation contains sensitive material at all. It trained for three epochs on roughly 714,000 samples, and a constrained Viterbi decoder resolves the label sequence at inference. Perplexity reports it leading twelve detectors on character F1 at 0.629 and on finding every recurring mention at 79.4%. Shipping a small, auditable gate model rather than naming a frontier model is the interesting decision: an enterprise can inspect or extend the boundary without having to trust the vendor alone.
def mask(text: str, spans: list) -> str:
out, cursor = [], 0
for s in sorted(spans, key=lambda x: x["start"]):
out.append(text[cursor:s["start"]])
out.append("[" + s["type"].upper() + "]")
cursor = s["end"]
out.append(text[cursor:])
return "".join(out)4. Long Context Is Where Privacy Leaks
The most honest number in the release is a failure mode. Long-context recall for the classifier drops to 0.687 past 10,000 characters. Read that again: on a long document, a single-pass gate misses roughly a third of the sensitive spans it should catch. Perplexity's mitigation is sliding-window decoding, which recovers recall to 0.965. Code sample 4 shows that pattern, and it generalises. Any single-pass classifier over a long input has a recall cliff, and a privacy boundary with a recall cliff is a boundary that fails exactly on the documents that matter most. If you build a local gate, measure recall by input length rather than only on average, and add a windowed pass before you trust it on legal or financial files.
WINDOW, STRIDE = 2048, 1024
def classify_long(text: str) -> list:
"""Single-pass recall collapses past ~10K chars; window it."""
spans, seen = [], set()
for start in range(0, max(len(text) - WINDOW, 0) + 1, STRIDE):
for s in classify(text[start:start + WINDOW])["spans"]:
key = (s["type"], start + s["start"])
if key not in seen:
seen.add(key)
spans.append({**s,
"start": start + s["start"],
"end": start + s["end"]})
return spans5. Where the Boundary Still Leaks
Three caveats deserve to be stated plainly. First, hybrid compute covers the steps the router judges sensitive; it does not make the whole task local, and Perplexity still chooses the local model for you. Second, the minimum hardware excludes a lot of machines, so the privacy guarantee is partial across any real fleet. Third, and most important, the gate is a classifier, not a proof: it can mask too little or too much, and its errors are silent unless you log them. Treat it as a strong default, not as a compliance control. Code sample 5 puts the boundary in configuration so it is reviewable, versioned, and testable rather than buried in application code, which is the difference between a design you can audit and a design you can only hope about.
hybrid_compute:
hardware_min_unified_memory_gb: 24
recommended_gb: 32
local_models: [gemma-4-e4b, qwen3.6-35b-a3b, pplx-qwen-3.8-27b]
gate:
model: pplx-pii-masking
window_tokens: 4096
on_sensitive: hand_to_local
outcomes: [keep_local, mask, refuse, ask]
log_decisions: true # silent gate errors are a compliance risk6. What to Copy
Copy the shape, not the product. Define explicit outcomes at the privacy boundary instead of a boolean. Ship a small, inspectable gate model you can audit and extend yourself. Measure recall by input length and add a windowed pass. Keep the boundary in configuration. And price the trade honestly: local inference costs no tokens, but it costs latency and a hardware floor. Perplexity demonstrated the same idea fully local on an NVIDIA DGX Spark on August 25, 2026, with an orchestrator, a subagent, and a harness running on-device, which is where this goes next. Privacy in agents will not be solved by a policy page. It will be solved by a router with a measurable gate, and that is now a shipped design any team can study.
The gate is the product
Measure recall by input length
📌 Frequently Asked Questions
What is Perplexity hybrid compute?
A feature announced September 1, 2026 for the Perplexity Mac app. A task starts in the cloud, and steps involving private files or sensitive data move down to a model running locally on your Mac.
What hardware do I need?
Apple silicon running macOS 15 or later, with 24 GB of unified memory as the minimum and 32 GB recommended. It is limited to Pro, Max, and Enterprise subscribers.
Which local models are available?
At launch: Gemma 4 E4B, Qwen3.6 35B-A3B, and a Perplexity post-trained Qwen variant; the setup flow points to a one-click download of PPLX Qwen 3.8 27B.
Is the PII gate open source?
Yes. Perplexity open-sourced pplx-pii-masking, the 0.6B token-classification model behind the gate, alongside PII-TRACE research, which lets enterprise IT teams audit or extend the privacy boundary.
What is the main limitation to know about?
Long-context recall for the classifier drops to 0.687 past 10,000 characters; sliding-window decoding recovers it to 0.965. Always measure recall by input length, not just on average.