Wo sonst die Cloud sitzt
Artikel 13 · Serie: Ein lokaler Coding-Agent mit apfel
Am Ende von Artikel 12 stand das Versprechen, den Agenten dorthin zu setzen, wo sonst die Cloud-Assistenten sitzen: in Xcode. Das ist der letzte Schritt der Reihe. Der Anlass dazu kommt von Apple selbst. Auf der WWDC26 hat das MLX-Team gezeigt, dass Xcode einen lokalen, OpenAI-kompatiblen Server als Coding-Provider ansprechen kann (Quelle: Apple, WWDC26-Session „Run local agentic AI on the Mac using MLX", 08.06.2026). Um zu verproben, ob apfel in genau diesen Slot passt, haben wir macOS 27 und Xcode 27 gezielt installiert. Das gibt zugleich die Gelegenheit, den beweglichen Grund aus Artikel 12 zu prüfen, ein Modell, das Apple ändern kann, wann es will. Also beginnt das Finale nicht mit einem Bau, sondern mit einer Messung.
macOS 27 bewegt das Fundament nicht
Die Sorge aus Artikel 12 war konkret: Ein Agent, der heute zuverlässig läuft, kann nach dem nächsten Update anders reagieren, und man sieht die Bewegung erst, wenn sie passiert ist. Ein Versionswechsel ist die Gelegenheit, das nachzusehen, statt es zu vermuten. Wir haben apfel nach dem Update gefragt, was es ausliefert (gemessen am 20. Juni 2026 auf macOS 27.0, Build 26A5353q).
| Aspekt | macOS 26.3 (Artikel 2) | macOS 27.0 (gemessen) |
|---|---|---|
| apfel-Version | 1.5.1 | 1.5.1 |
| Modell-ID | apple-foundationmodel | apple-foundationmodel |
| Kontextfenster | 4096 Token | 4096 Token |
| Tool-Calling, Constrained Output | vorhanden | vorhanden |
| Serve, OpenAI-kompatibel | ja | ja |
apfel --model-info nennt weiterhin apple-foundationmodel, context: 4096 tokens, framework: FoundationModels (macOS 26+). Der Server startet, antwortet, streamt. Nichts an der Oberfläche, an der unser Agent hängt, hat sich verschoben. Der Wechsel von 26.3 auf 27 hat für unseren Zweck nichts verändert.
Das ist eine gute Nachricht, aber keine Garantie. Apple kann das Modell beim nächsten Mal austauschen, das Kontextfenster verändern, die Guardrails neu justieren. Wir haben in dieser Reihe gesehen, dass beides Verhalten ist, das ein Update verschieben kann (Artikel 7 und 8). Dass es diesmal nicht passiert ist, heißt nicht, dass es nicht passieren wird. Es heißt nur, dass wir auf demselben Modell weiterbauen können, mit dem wir angefangen haben.
Der Slot, in dem sonst die Cloud sitzt
Xcode 27 hat einen Platz für Sprachmodelle, der in den Vorjahren noch nicht da war. Unter Settings, im Reiter Intelligence, lassen sich Chat-Provider hinzufügen. In der Voreinstellung sind das die großen Namen, Anthropic und OpenAI, die ihre Modelle aus der Cloud liefern. Apple hat denselben Mechanismus aber für lokale Server geöffnet. Genau das führte die eingangs genannte WWDC26-Session vor, einen lokalen, OpenAI-kompatiblen Server in Xcode eintragen und ihn Bugs im offenen Projekt fixen lassen. Der Server in der Demo war MLX-LM. Was dort steckt, ist austauschbar, solange es das Protokoll spricht.
apfel-Serve spricht dieses Protokoll. Das war die Entscheidung aus Artikel 2: kein direkter Framework-Aufruf, sondern ein OpenAI-kompatibler Endpunkt, den jedes SDK versteht, das einen solchen erwartet. Genau diese Entscheidung zahlt sich jetzt aus. Der Dialog „Add a Model Provider" bietet einen Umschalter zwischen „Internet Hosted" und „Locally Hosted". Wählt man Locally Hosted, fragt Xcode nach einem Port und einer Beschreibung. Kein API-Key, kein Token, kein Modellname. Wir tragen den Port ein, auf dem apfel lauscht, und geben dem Eintrag einen Namen.
Hier liegt ein Trugschluss vor, über den wir gestolpert sind. apfels Standard-Port ist 11434, und das ist zugleich der Standard-Port von Ollama. Xcode bringt für lokale Modelle eine Ollama-Anbindung mit, und die spricht Ollamas eigenes Protokoll auf /api/chat. Man könnte erwarten, dass der Locally-Hosted-Slot auf demselben Port denselben Ollama-Pfad anspricht und apfel, das nur OpenAI-Pfade bedient, ins Leere läuft. Das tut er nicht. Der Mitschnitt am apfel-Server zeigt, was Xcode wirklich aufruft: POST /v1/chat/completions, im Streaming-Modus, mit Status 200 (gemessen, macOS 27.0 / Xcode 27.0, 20.06.2026). Der Locally-Hosted-Slot spricht OpenAI, nicht Ollama. apfel passt hinein, ohne dass wir etwas anpassen müssen, und weil der Dialog kein Token-Feld hat, lassen wir apfel ohne Token-Pflicht laufen.
Damit ist das Souveränitäts-Statement der Reihe technisch eingelöst. In dem Feld, in dem Xcode sonst Claude oder ChatGPT aus der Cloud holt, steht jetzt ein Modell, das auf dem eigenen Mac läuft, nichts kostet und nichts nach außen gibt. Der erste kurze Prompt aus Xcodes Coding-Chat kommt durch, das Modell antwortet, die Antwort erscheint im Editor.
Verbunden, aber überfordert
Die Verknüpfung ist das Leichte. Der schwere Teil zeigt sich beim ersten ernsthaften Prompt. Wir öffnen eine Swift-Datei und bitten den Assistenten, sie zu erklären. Was zurückkommt, ist keine Erklärung, sondern eine Floskel: das Modell habe nicht genug Kontext, man möge doch den Code bereitstellen. Der Mitschnitt zeigt das Gegenteil. Im Request steckt die Datei, gut sechstausend Zeichen Swift, mitgeschickt als Kontext (gemessen). Das Modell hat den Code vor sich und antwortet, als hätte es ihn nicht. Der Request lag bei 2578 Prompt-Token, deutlich unter dem 4096-Fenster. Es war also nicht zu eng. Es war zu schwer.
Der Grund liegt im System-Prompt, den Xcode mitschickt. Er ist knapp viertausend Zeichen lang, rund tausend Token, und verlangt vom Modell einen mehrstufigen Arbeitsgang: erst in Prosa durchdenken, welche Typen fehlen, dann das Projekt danach durchsuchen, auf Nachlieferung warten, und erst dann antworten. Das ist die Choreografie, die ein großes Cloud-Modell mitmacht. Unser Foundation Model mit seinen berichteten drei Milliarden Parametern macht sie nicht mit. Es fällt in die generische Antwort zurück. Das ist exakt die Grenze, die Artikel 6 vermessen hat: kleine, lokale Aufgaben ja, mehrschrittige Choreografie nein.
Der zweite Versuch läuft gegen eine andere Wand. Wir starten eine frische Unterhaltung, lassen die Datei offen und bitten erneut, sie zu erklären. Diesmal schickt Xcode die ganze Datei, nicht nur einen Ausschnitt. Der Request wächst auf gut dreiunddreißigtausend Zeichen, weit jenseits dessen, was in 4096 Token passt. apfel weist ihn sauber ab, mit Status 400 und einer klaren Meldung, die Xcode wörtlich durchreicht: „Input exceeds the 4096-token context window. Shorten the conversation history." (gemessen).
Damit haben wir beide Versagensarten gesehen, und sie ergänzen sich zu einem Bild.
| Fall | Was Xcode schickt | Was apfel tut | Woran es liegt |
|---|---|---|---|
| Ausschnitt der Datei | passt ins Fenster (2578 Token) | antwortet, aber mit Floskel | Modellfähigkeit |
| Ganze Datei | sprengt das Fenster (~33000 Zeichen) | lehnt mit 400 ab | Kontextfenster |
Beide Male liegt es nicht an der Verbindung und nicht am Protokoll. apfel antwortet korrekt, einmal mit einer Antwort, einmal mit einem sauberen Fehler. Die Grenze ist das Modell. Es ist zu klein für die Aufgabe, die Xcode an einen Coding-Assistenten stellt, und sein Fenster ist zu eng für die Dateien, die dabei anfallen.
Hier antwortet apfel-Serve, nicht unser Agent
Der Locally-Hosted-Weg umgeht allerdings etwas. In Xcode antwortet apfel-Serve, das nackte Foundation Model hinter einem OpenAI-Endpunkt. Es ist nicht der Agent, den wir über zwölf Artikel gebaut haben. Der Plan/Act/Observe-Loop, das eng geführte Tool-Calling, das Constrained Editing aus den Artikeln 4 bis 7, der ContextManager aus Artikel 8, das alles steht in diesem Pfad nicht zwischen Xcode und dem Modell. Xcode redet direkt mit dem Modell und bringt seine eigene Agentik mit, die unser Modell überfordert.
Der Weg, auf dem unser gebauter Agent ins Spiel käme, ist der andere, und er führt über das Model Context Protocol. Dort gibt es zwei Richtungen, die man sauber auseinanderhalten muss. In der einen ist Xcode der MCP-Client und spricht einen externen Agenten an, der Werkzeuge und Fähigkeiten bereitstellt. In der anderen ist unser Agent der MCP-Client und nutzt die Werkzeuge, die Xcodes eigener MCP-Server anbietet, Projektzugriff, Diagnostics, Build-Informationen. Beide Richtungen sind in Xcode 27 angelegt, und beide haben wir an dieser Stelle nicht geprüft. Sie sind der offene Rand des Finales, kein erledigter Punkt. Was wir belegen können, ist der direkte Provider-Slot. Was darüber hinausgeht, der vollständige Agent in Xcode über MCP, bleibt der nächste Schritt, nicht dieser. Eines verschiebt MCP dabei nicht. Unser Agent nutzt dasselbe Foundation Model, also stößt er auch über diesen Weg an dieselbe Decke, die wir gerade vermessen haben. MCP ändert den Anschluss, nicht die Stärke des Modells.
Einen Gedanken zum Schluss
Der lokale Agent läuft jetzt wirklich dort, wo sonst die Cloud sitzt. Das kostet nichts, verlässt den Mac nicht, und ist mit einem Port und einer Beschreibung eingerichtet. Für jemanden, der einen Eindruck davon will, wie sich ein lokales Modell im Editor anfühlt, ohne Key, ohne Anbieter, ist das ein niedrigschwelliger Einstieg. Für ernsthafte Coding-Arbeit in Xcode reicht das Modell nicht. Das haben wir geprüft und ausprobiert.
Genau hier schließt sich der Kreis zum Dreieck aus Artikel 12. Apfels Foundation Model ist die niedrigschwellige Ecke, lokal und genügsam, dafür klein und geliehen. Wer in Xcode mehr will, landet bei einem größeren Modell, also bei MLX mit einem offenen Modell und etwas mehr RAM, oder zurück in der Cloud. Und der Übergang dahin ist kein Neubau. Xcodes Locally-Hosted-Slot spricht dasselbe OpenAI-Protokoll wie apfel-Serve und wie der MLX-LM-Server. Ein besseres lokales Modell bedeutet denselben Slot, einen anderen Port. Was wir in dieser Reihe gelernt haben, gilt über das Modell hinaus, das wir benutzt haben. Wir haben nicht ein Modell verstanden, sondern wie man gegen ein Protokoll baut, und dieses Wissen wandert mit, wenn das Fundament sich verschiebt. Diesmal hat es das nicht. Beim nächsten Mal sehen wir es, wenn es passiert, und nehmen den Agenten mit.
Vorheriger Artikel: Souveränität auf geliehenem Fundament. Dieser Artikel ist der Abschluss der Reihe. Die Xcode-Anbindung über den Locally-Hosted-Provider ist Konfiguration, kein neuer Code; der Agent-Stand bleibt bei v1.0. Die gemessenen Belege stehen im Integrations-Snapshot vom 20.06.2026.