Skip to main content

Phone Smart Layer — Privacy

When ZeroClaw accesses personal data from your phone, the Phone Smart Layer ensures that raw personal data never leaves your device. Only inferred, structured summaries are forwarded to the LLM provider.

The Core Guarantee

Raw personal data never leaves your device.

SMS bodies, contact names, call numbers, health metrics, GPS coordinates, and notification text are processed entirely inside the ZeroClaw binary running on your phone. Only the inferred meaning — structured labels, counts, and classifications — is forwarded to the LLM.

Why This Matters

ZeroClaw can be configured to use any LLM provider: OpenAI, Anthropic, Mistral, a local Ollama instance, or a self-hosted endpoint. Without the smart layer, asking the agent "what bills do I have this week?" would require sending your entire SMS inbox to that provider verbatim.

With the smart layer, the same question is answered by sending:

{
"bills": [{ "amount": "$1,400", "due": "March 31" }],
"otp_codes_present": 2,
"spam_filtered": 3,
"replies_needed": [{ "urgency": "high", "has_bill": false }],
"summary": "8 messages: 1 bill(s), 1 repl(ies) needed, 0 financial alert(s), 2 OTP(s), 3 spam"
}

No sender numbers. No message text. No contact names.

Architecture

┌─────────────────────────────────────────────────────────────┐
│ Your Phone │
│ │
│ ┌──────────────────┐ ┌──────────────────────────────┐ │
│ │ PhoneBridgeServer│ │ ZeroClaw binary │ │
│ │ (port 9092, │ │ │ │
│ │ loopback only) │◄─────│ phone_smart tools │ │
│ │ │ │ ┌──────────────────────────┐│ │
│ │ • SMS │ │ │ 1. fetch raw data ││ │
│ │ • Calendar │ │ │ (loopback HTTP) ││ │
│ │ • Notifications │ │ │ 2. run heuristics in Rust ││ │
│ │ • Health │ │ │ 3. build structured ││ │
│ │ • Location │ │ │ summary ││ │
│ │ • Call log │ │ │ 4. discard raw data ││ │
│ │ • Device/sensor │ │ └──────────────────────────┘│ │
│ └──────────────────┘ └──────────────┬───────────────┘ │
│ │ │
└───────────────────────────────────────────┼──────────────────┘
│ structured summary only

┌────────────────────────┐
│ External LLM API │
│ (OpenAI / Anthropic / │
│ local Ollama / etc.) │
└────────────────────────┘

The bridge server is bound exclusively to 127.0.0.1:9092. It is unreachable from the network. ZeroClaw communicates with it over loopback only, using a randomly-generated bearer token that is rotated on each app launch.

What Each Tool Sends to the LLM

Daily Brief (phone_day_brief)

Data sourceRaw data fetchedWhat reaches the LLM
Recoveryscore (0-100), sleep duration, HRV, resting HRscore bucket ("good"/"fair"/"poor"/"optimal"), up to 2 insight strings with no raw numbers
SMSfull message bodies, sender numbers, timestampsbill amounts + due-date hints, reply count, financial alert count — no body text, no numbers
Notificationspackage names, title, full notification textcount by category (financial, messaging, etc.), urgent count — no text
Calendarevent titles, descriptions, start/end timesevent count today, travel keyword detected (boolean), next free 1h block as time range
Device contexttimezone offset, battery %, charge status, network typetimezone offset (used for time-of-day label only), battery label, network type label
Carrieroperator name, roaming flag, call stateroaming: true/false

Never sent: sender phone numbers, message bodies, contact names, exact health numbers, full event titles or descriptions, exact battery %, GPS coordinates.

SMS Brief (phone_sms_brief)

Data sourceRaw data fetchedWhat reaches the LLM
SMSfull message bodies, sender addresses, timestampsbill list (amount + due hint), reply list (urgency label), financial alert list (amount + type), OTP count, spam count

Never sent: message body text, sender phone numbers or names, exact timestamps.

OTP messages are counted but immediately discarded — their codes are never surfaced in any output field.

Communications Summary (phone_comms_summary)

Data sourceRaw data fetchedWhat reaches the LLM
SMSmessage bodiesurgent count, reply-needed count, bill count
Notificationspackage names, notification textcounts by category, urgent count
Call lognumbers, call type, timestamps, durationmissed call count in last 24h

Never sent: phone numbers, message bodies, notification text, contact names, call duration.

Context Snapshot (phone_context_now)

Data sourceRaw data fetchedWhat reaches the LLM
Device contextbattery %, charge status, network type, timezone offset, calendar eventsbattery label, connectivity label, in_meeting boolean, time-of-day label, weekend boolean
Carrierroaming flag, call statelocation_type: "travel"/"local"
Audio profileDND mode, ringer mode, volume levelsDND mode label, ringer mode label
Activitysteps since rebootsteps_available: true/false

Never sent: exact GPS coordinates (not fetched at all by this tool), exact battery percentage, network SSID, operator name, step count, volume levels.

Data Retention

The smart tools are stateless. Each call:

  1. Fetches data over loopback.
  2. Processes it in Rust stack/heap memory.
  3. Constructs the output JSON.
  4. Returns — all intermediate data is dropped when the function returns.

Nothing is written to disk. Nothing is cached. No database entry is created. Raw fetched values are local variables that go out of scope and are freed by the allocator before the HTTP response to the LLM provider is even assembled.

Classification Heuristics

All classification work happens inside the ZeroClaw binary using deterministic Rust code:

HeuristicHow it works
OTP detectionKeyword match ("code", "otp", "one-time", "pin") + regex \b\d{4,8}\b
Spam detectionKeyword list ("click here", "free gift", "lottery", etc.)
Bill detectionAmount regex (currency symbols + numeric pattern) + keyword match ("due", "invoice", "bill", "rent")
Urgency classificationKeyword tiers: "overdue"/"final notice"/"action required" → high; "reminder"/"due soon" → medium
Notification categoryAndroid package name substring matching ("whatsapp" → messaging, "coinbase" → financial, etc.)
Recovery labelScore range: 0–39 → poor, 40–59 → fair, 60–79 → good, 80+ → optimal
Time of dayUTC offset from device + Unix timestamp → local hour → morning/afternoon/evening/night

No machine learning. No on-device model. No network call. Pure deterministic Rust — auditable, reproducible, and fast (sub-millisecond per message).

What Is Not Protected by This Layer

The smart layer is a privacy filter for contextual data tools. It does not cover:

  • Direct raw toolsphone_sms_read, phone_health_read, phone_notifications_get, etc. If the LLM explicitly calls these, raw content is returned. The agent's system prompt and capability configuration control whether these are available.
  • Screen automationphone_a11y_screenshot and related tools operate on screen content. Their output is constrained by capability gating, not this layer.
  • The LLM provider's own privacy policy — The structured summaries are sent to whatever provider the user configured. 0x01 cannot control what the provider does with the data it receives.

Capability Gating

Every bridge endpoint is guarded by a capability flag in Android SharedPreferences. Capabilities can be toggled per-category in Settings → Phone Bridge:

CapabilityControls
messagingSMS read and send
contactsContacts read and write
locationGPS location
cameraCamera capture
microphoneAudio recording
screenAccessibility tree and screen capture
callsCall log and call screening
calendarCalendar read and write
mediaPhotos and documents

If a capability is disabled, the bridge returns 403 capability_disabled and the smart tool treats that data source as absent — no error is surfaced to the LLM.

Threat Model

ThreatMitigated by
LLM provider reads SMS bodiesSmart layer — bodies never leave device
LLM provider learns contact namesSmart layer — names never leave device
LLM provider learns exact health numbersSmart layer — only score labels and insights are sent
LLM provider learns GPS coordinatesSmart layer — location is not fetched by smart tools; only roaming flag
Network attacker intercepts bridge trafficBridge binds to 127.0.0.1:9092 only; loopback is not routable
Malicious process reads bridge dataBearer token required; token is random and rotated per app launch
Smart layer leaks raw data in error pathsAll bridge calls return Option — failures produce absent fields, not raw data in errors