Simon-Pierre Boucher
All apps & projects
Poche icon
iOS App
Swift

Poche

Your agent, on your device — offline, private, yours

A personal agent living entirely on the iPhone: streaming chat over Apple Foundation Models that creates reminders, events, notes, and tasks behind explicit confirmation cards. No API, no server, no account.

41

Swift files, ~2,930 lines

21/21

automated tests green

7

tools exposed to the model

0

network requests in the AI path

4,096

token context, actively managed

~3B

parameters, on the Neural Engine

Overview

Poche is a personal agent whose only generative engine is Apple Foundation Models — the ~3B-parameter Apple Intelligence model running on the device's Neural Engine. The founding rule: if a feature can't be done on-device, it isn't done. There is no cloud fallback, no degraded promise.

It's a streaming chat that acts: creating reminders and calendar events through EventKit, saving notes and tasks in SwiftData, and recalling your data through local semantic search (NLEmbedding). The model never causes a side effect — it proposes a tool call, and the app validates, displays a confirmation card, and executes only after the user confirms. No code path writes without traversing the confirmation layer.

The central engineering problem is the 4,096-token context window: system instructions, tool schemas, history, and the response all share it. Poche measures continuously, condenses the conversation at 70% through a separate @Generable summarization call, and recycles the session invisibly — the user never sees an error. A tripwire test registers a URLProtocol spy and fails if a single network request leaves during agent exercises.

Key Features

An agent that acts

Creates reminders, calendar events, notes, and tasks through EventKit and SwiftData — from natural conversation, in streaming.

Non-bypassable confirmation

The model proposes; the user disposes. Every write crosses a confirmation card with dates resolved and validated in Swift — no expert mode to disable it.

Context budget engine

Continuous token measurement, condensation at 70% via a separate @Generable call, and invisible session recycling — a local chat that never breaks.

Local semantic search

Notes, tasks, and conversation summaries indexed with NLEmbedding — long-term memory retrieved on demand, entirely on-device.

Zero network, proven

A tripwire test registers a URLProtocol spy and fails if a single request leaves the device while the agent's tools and search are exercised.

On-device dictation

SFSpeechRecognizer with on-device recognition required — if the device can't transcribe locally, the mic button doesn't exist. No server fallback.

How It Works

  1. Stream the conversation

    A LanguageModelSession streams responses with a first-token target under 400 ms, backed by versioned system instructions costing a measured ~230 tokens.

  2. Propose, never execute

    Tools validate arguments hostilely (dates resolved in Swift, titles truncated, bounds checked) and emit proposals to the ConfirmCenter — the only write path is the ActionExecutor, after user confirmation.

  3. Manage the 4,096-token budget

    A pessimistic estimator drives a discreet context gauge; at 70% the conversation is condensed by a separate structured call and the session recycled with the summary plus the last 3 turns.

  4. Externalize long memory

    Summaries persist in SwiftData and come back on demand through searchMyData — the agent remembers across sessions without ever growing the context.

  5. Handle every model state

    Available, device-not-eligible, Apple Intelligence off, model downloading — each gets its own screen and action, and guardrail refusals are calm UI states, never raw errors.

Tech Stack

Platform

Swift 6 (strict concurrency)
SwiftUI + @Observable
iOS 26+
XcodeGen

Intelligence

Apple Foundation Models (~3B)
@Generable / @Guide schemas
NLEmbedding semantic index
On-device SFSpeechRecognizer

Data & system

SwiftData
EventKit
App Intents
Share Extension
Data Protection encryption

Highlights

  • No code path writes without traversing the confirmation layer — verified by the tool-pattern test suite
  • 21/21 tests green under Swift 6 strict concurrency, including the zero-network tripwire
  • Tool outputs are capped (~200 tokens) because one tool returning 30 events kills a 4K session
  • Date resolution happens in Swift, never in the model — displayed in clear text on every confirmation card
  • TestFlight 1.0.0 uploaded to App Store Connect (ai.spboucher.poche)
  • The whole agent — chat, tools, memory, dictation — fits in ~2,930 lines of Swift

Explore Poche

A 100% on-device personal agent — the full source is on GitHub.