PocketBrains
PocketBrains app icon

On-device AI agent for iOS 26

A private chief of staff for your tasks, projects and notes. Nothing leaves the phone.

One thread, a 24-tool agent that plans multi-step requests, answers from your notes with citations, and can undo anything it did. Apple's on-device model when available, an optional open model, and a deterministic router that always works.

Evaluation Architecture View on GitHub

Tests passing
129
Swift Testing, 129 tests in 18 suites, CI simulator
Held-out paraphrases, end-to-end
39.6%
53 utterances never used for tuning (deterministic brain)
Tool trimming recall@8
96.3%
expected tool kept when offering 8 of 24 tools, 243 cases
Notes retrieval recall@3
96.7%
BM25, 61 synthetic questions

Evaluation

Parsed from the EVALJSON lines of the iOS test job in CI run 37745540170, with the "before" column from run 37721075662 (the v0.3 branch before any router change). All corpora are synthetic and written for the eval. Nothing below is typed by hand. These numbers describe the deterministic brain and the tool trimmer only; no Foundation Models or MLX accuracy is claimed.

held-out never used to tune rules, misses never itemized · dev rules may be tuned on it · gated must stay at 100% or CI fails.

Deterministic router

Every utterance runs through the deterministic brain's real entry point against a freshly seeded in-memory store. Tool accuracy: the right tool (for compound requests, the exact sequence). End-to-end: right tool, every call succeeded, and the resulting state is right. The v0.3 held-out row is the honest generalization number.

SplitRolenTool (before)End-to-end (before)Tool accuracyEnd-to-end
v1 canonicalgated documented phrasing (v0.1)29100.0%100.0%100.0%100.0%
v1 paraphrasedev seen during v0.2 tuning11100.0%100.0%100.0%100.0%
v2 canonicalgated documented phrasing (v0.2 tools)30100.0%100.0%100.0%100.0%
v2 compoundgated multi-step requests12100.0%100.0%100.0%100.0%
v2 dev paraphrasedev v0.2 dev split23100.0%100.0%100.0%100.0%
v0.2 held-out (reported)held-out frozen; score published with v0.23438.2%35.3%50.0%47.1%
v0.3 dev paraphrasedev v0.3 dev split, the only one v0.3 tuned on515.9%5.9%100.0%100.0%
v0.3 held-out (frozen)held-out frozen before v0.3 router work; never tuned5337.7%30.2%47.2%39.6%
original 40 (v1) the v0.1 corpus, for continuity40100.0%100.0%100.0%100.0%
overall every case24358.0%56.0%81.5%79.4%

Tool trimming for the Foundation Models brain (recall@k)

Share of cases whose expected tool (every step, for compound requests) is inside the set ToolSelector would offer the on-device model, out of 24 tools. This measures the trim, not the model. The selector reuses the deterministic grammar, so canonical rows are not independent of it.

SplitRolenrecall@6recall@8
v1 canonicalgated29100.0%100.0%
v1 paraphrasedev11100.0%100.0%
v2 canonicalgated30100.0%100.0%
v2 compoundgated12100.0%100.0%
v2 dev paraphrasedev23100.0%100.0%
v0.2 held-out (reported)held-out3482.4%88.2%
v0.3 dev paraphrasedev51100.0%100.0%
v0.3 held-out (frozen)held-out5386.8%90.6%
overall24394.7%96.3%

Ask your notes (retrieval and citations)

Synthetic fixture of 22 notes and 61 questions, each with one relevant note and an answer span. recall@k: the relevant note is among the notes of the top k passages. Citation faithfulness: every [n] in the extractive answer follows a sentence found in a retrieved passage of note n. Span attribution: when the answer contains the span, its [n] points at a passage that contains the span.

Methodnrecall@1recall@3Answer contains spanCitation faithfulnessSpan attribution
bm256193.4%96.7%96.7%100.0% of 130100.0%

Retrieval eval, hybrid: skipped (asset unavailable).

Routing plus tool execution latency on the CI simulator (in-memory store): p50 6.71 ms, p95 15.68 ms. Latency varies between runner instances; accuracy is deterministic.

In 60 seconds

Demo: a short device recording (plan card, Undo, cited answer) will go here as docs/img/demo.gif. Screenshots are not yet in the repository either; see Screenshots.

Architecture

flowchart LR
    U["User utterance<br/>or Siri / Shortcuts"] --> O["AgentOrchestrator<br/>one journal group per turn"]
    O --> S{"Which brain?"}
    S -->|"Apple Intelligence"| FM["Foundation Models<br/>native Tool calling +<br/>@Generable plans"]
    S -->|"MLX build flag"| MLX["MLX Qwen3-4B<br/>JSON tool calls"]
    S -->|"otherwise"| DP["Deterministic router<br/>lexicon + NLTagger lemmas<br/>+ slot frames"]
    FM -.->|"generation fails"| DP
    FM --> PL["Planner<br/>CompoundPlanner / PlanExecutor<br/>$N references, postconditions"]
    MLX --> TP["ToolCallParser<br/>one or many calls"] --> PL
    DP --> PL
    PL --> TB["ToolBox<br/>24 tools"]
    FM --> TB
    TB --> J["Action journal<br/>inverse per mutation"]
    J --> UN["UndoEngine<br/>atomic per plan"]
    TB --> RAG["NotesRAG<br/>chunks, BM25 + NLEmbedding,<br/>cited answers"]
    TB --> INT["Integrations (opt-in)<br/>EventKit Calendar read,<br/>Reminders export"]
    TB --> DS["DataServices<br/>single write path"]
    UN --> DS
    DS --> DB[("SwiftData<br/>on device")]
    DS --> W["App Group snapshot"] --> WG["Today widget"]
    DS --> V["Today / Projects /<br/>Knowledge spaces"]

Every brain emits the same event stream (tool started, tool finished, text snapshot, done); plans use it too, as a plan card that updates in place plus numbered step cards, so the UI never knows which brain answered. If a model reports itself available but fails to generate, the orchestrator swaps to the deterministic router and answers the same prompt. Agent, views, Siri intents and the widget feed all go through one service layer. Details: docs/ARCHITECTURE.md.

Why on-device

On-device (PocketBrains) Cloud assistant
Client and personal data Never leaves the phone Sent to a provider
Works offline / Airplane Mode Yes No
Per-request cost None, no backend Per token
Reasoning headroom Smaller model, so its job is kept small: pick a tool, fill arguments Large models, long context
Device coverage Apple Intelligence devices, plus MLX and deterministic tiers Any connected device

The design keeps the model's job narrow and puts the data work in deterministic, tested code. That is what makes a ~3B on-device model sufficient for this product.

Build and run

Requirements: a Mac with Xcode 26 (iOS 26 SDK) and XcodeGen. The Xcode project is generated from project.yml and is not committed.

brew install xcodegen
git clone https://github.com/seanmcrae/pocketbrains-app.git
cd pocketbrains-app
xcodegen generate
open PocketBrains.xcodeproj

Run on an iOS 26 simulator or device. On hardware with Apple Intelligence the Foundation Models brain engages automatically; elsewhere, including the simulator, the deterministic router answers. Settings, Intelligence lets you force the deterministic brain. Calendar and Reminders stay off until you enable them in Settings, Integrations. The Today widget builds unsigned in CI; to run it on a device, sign both the app and PocketBrainsWidget with your team and keep the App Group group.com.pocketbrains.shared on both (declared in project.yml). To build the optional MLX backend, follow the comments in project.yml (adds the mlx-swift-examples package and the POCKETBRAINS_MLX flag; the model is a ~2.3 GB download on first use).

Tests, exactly as CI runs them:

xcodebuild test -project PocketBrains.xcodeproj -scheme PocketBrains \
  -destination 'platform=iOS Simulator,name=iPhone 17 Pro' \
  -parallel-testing-enabled NO CODE_SIGNING_ALLOWED=NO

Limitations

More