<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Eric Marchand</title>
    <description>The latest articles on DEV Community by Eric Marchand (@phimage).</description>
    <link>https://dev.to/phimage</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4024969%2Fa92be3e5-71d8-48d9-8120-5ba53809e4ae.png</url>
      <title>DEV Community: Eric Marchand</title>
      <link>https://dev.to/phimage</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/phimage"/>
    <language>en</language>
    <item>
      <title>Debugging is also clicking 🖱️</title>
      <dc:creator>Eric Marchand</dc:creator>
      <pubDate>Mon, 10 Aug 2026 03:50:10 +0000</pubDate>
      <link>https://dev.to/phimage/debugging-is-also-clicking-n8g</link>
      <guid>https://dev.to/phimage/debugging-is-also-clicking-n8g</guid>
      <description>&lt;p&gt;In the last couple of posts I let agents debug over &lt;a href="https://phimage.github.io/blog/dap-for-agents" rel="noopener noreferrer"&gt;DAP&lt;/a&gt; —&lt;br&gt;
breakpoints, step over, continue. That's real debugging. But it's only half of it.&lt;br&gt;
When I debug something for real, I also &lt;em&gt;click&lt;/em&gt;: I press the button and watch what&lt;br&gt;
happens, read the dialog, notice the toggle is greyed out. No backtrace ever tells&lt;br&gt;
you the &lt;strong&gt;Save&lt;/strong&gt; button never enabled. So — can the agent do that half too?&lt;/p&gt;

&lt;h2&gt;
  
  
  The web is the easy case
&lt;/h2&gt;

&lt;p&gt;Browsers are automatable by design. Most agent tools ship their own browser or&lt;br&gt;
drive an external one; point &lt;a href="https://playwright.dev" rel="noopener noreferrer"&gt;Playwright&lt;/a&gt; at a page and&lt;br&gt;
every element has a stable, queryable handle. The DOM &lt;em&gt;is&lt;/em&gt; an accessibility tree&lt;br&gt;
wearing a different hat — roles, labels, structure, all there for the reading. For&lt;br&gt;
the web, this half of debugging is close to solved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native apps are another game
&lt;/h2&gt;

&lt;p&gt;There's no DOM. When the agent has nothing to go on, it falls back to the eyeball&lt;br&gt;
approach: take a screenshot, let the model look, maybe run OCR or a pre-analysis&lt;br&gt;
pass to label what's on screen. It works — and sometimes it's the only option — but&lt;br&gt;
it's brittle (a few pixels off and the click misses) and it burns tokens describing&lt;br&gt;
pictures.&lt;/p&gt;

&lt;p&gt;I ran into this by accident. I once wrote a tiny skill whose only job was to&lt;br&gt;
screenshot a running 4D form and stitch an animated GIF for a README —&lt;br&gt;
&lt;a href="https://github.com/e-marchand/skills/blob/main/4d-capture-gif/SKILL.md" rel="noopener noreferrer"&gt;4d-capture-gif&lt;/a&gt;.&lt;br&gt;
Then I noticed Claude Code reaching for it to &lt;em&gt;debug&lt;/em&gt;: the skill also reports a bit&lt;br&gt;
of the form's structure — where the buttons are — so the agent knows where to&lt;br&gt;
click. For simple cases it genuinely works. But screenshots-plus-coordinates is not&lt;br&gt;
the thing I want to build on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cleaner path: read the tree, don't look at pixels
&lt;/h2&gt;

&lt;p&gt;Instead of staring at the screen, read the UI tree directly. On macOS you can&lt;br&gt;
script the Accessibility API from Python (pyobjc), and there are automation&lt;br&gt;
libraries to help. Now you're clicking &lt;em&gt;element #37, the "Save" button&lt;/em&gt; instead of&lt;br&gt;
&lt;em&gt;coordinate (412, 260), and hope&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A couple of open-source tools are pushing exactly here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/lahfir/agent-desktop" rel="noopener noreferrer"&gt;&lt;strong&gt;agent-desktop&lt;/strong&gt;&lt;/a&gt; — a native CLI that
exposes any app's accessibility tree as &lt;code&gt;snapshot&lt;/code&gt; / &lt;code&gt;click&lt;/code&gt; / &lt;code&gt;type&lt;/code&gt; / &lt;code&gt;press&lt;/code&gt;
with structured JSON. No screenshots, precise element references. Its &lt;em&gt;progressive
skeleton&lt;/em&gt; mode drills down the hierarchy instead of dumping it whole, cutting
prompt tokens dramatically (they cite 78–96% on dense apps). And it ships a C-ABI
library, so Python, Swift, Go or Node can call it in-process instead of shelling
out per action. (macOS today, more platforms in progress; needs Accessibility and
Screen Recording permissions.)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/AmberSahdev/Open-Interface" rel="noopener noreferrer"&gt;&lt;strong&gt;Open Interface&lt;/strong&gt;&lt;/a&gt; — the other end
of the spectrum: an LLM (GPT-4o/4V, Gemini…) reads your request, drives the real
mouse and keyboard, and re-screenshots to course-correct. Demos include solving
Wordle and editing a Google Doc. End-to-end agentic desktop use, screenshots in
the loop.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Faire d'une pierre deux coups
&lt;/h2&gt;

&lt;p&gt;Here's the thing I keep circling back to. If you build a native macOS or iOS app and&lt;br&gt;
you &lt;em&gt;draw your own components&lt;/em&gt;, there's nothing underneath them — the agent has no&lt;br&gt;
tree to grab, so it's back to pixels. But if you implement the accessibility tree&lt;br&gt;
for those custom components, you get &lt;em&gt;faire d'une pierre deux coups&lt;/em&gt; — kill two birds&lt;br&gt;
with one stone:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;an AI agent can drive your UI by real element references, and&lt;/li&gt;
&lt;li&gt;— the one that actually matters — people using VoiceOver, Switch Control or Voice
Control can use your app.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The automation win comes for free, riding on the accessibility win. That's a rare&lt;br&gt;
kind of alignment: the boring, decades-old right-thing-to-do turns out to be the&lt;br&gt;
same work that makes your app agent-ready.&lt;/p&gt;

&lt;p&gt;And Apple already tells you how, for Cocoa, UIKit and even SwiftUI. The WWDC26&lt;br&gt;
session &lt;a href="https://developer.apple.com/videos/play/wwdc2026/220" rel="noopener noreferrer"&gt;&lt;em&gt;Refine accessibility for custom controls&lt;/em&gt;&lt;/a&gt;&lt;br&gt;
walks through labels, values, adjustable actions and custom actions for exactly this&lt;br&gt;
case — their example turns a custom coffee-dispenser control that assistive tech&lt;br&gt;
could only read as a bare "button" into an adjustable one you swipe to change.&lt;br&gt;
There's written guidance too — AppKit's&lt;br&gt;
&lt;a href="https://developer.apple.com/documentation/appkit/custom-controls" rel="noopener noreferrer"&gt;custom controls documentation&lt;/a&gt; —&lt;br&gt;
and a whole &lt;a href="https://developer.apple.com/videos/accessibility-inclusion/" rel="noopener noreferrer"&gt;library of accessibility sessions&lt;/a&gt;&lt;br&gt;
behind it.&lt;/p&gt;

&lt;p&gt;A 4D aside, and a note to self: I suspect that in 4D a form window is drawn as&lt;br&gt;
essentially one big view, with no accessibility tree exposed underneath — which&lt;br&gt;
would explain why the agent has to fall back to screenshots. That's something I want&lt;br&gt;
to investigate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Something will emerge
&lt;/h2&gt;

&lt;p&gt;LLM-driven desktop automation is a moving space — open tooling and academic interest&lt;br&gt;
are both growing, and I'd bet the right abstraction hasn't shown up yet. Something&lt;br&gt;
will. Meanwhile, if you're drawing custom UI, the move is clear enough: give it an&lt;br&gt;
accessibility tree. The people who rely on it need it — and it happens to be exactly&lt;br&gt;
what an agent needs to help you debug your own app. 🖱️&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>debugging</category>
      <category>a11y</category>
    </item>
    <item>
      <title>Debugging with agents, à l'envers: MCP in, or DAP out? 🐛</title>
      <dc:creator>Eric Marchand</dc:creator>
      <pubDate>Sun, 09 Aug 2026 06:14:43 +0000</pubDate>
      <link>https://dev.to/phimage/debugging-with-agents-a-lenvers-mcp-in-or-dap-out-5880</link>
      <guid>https://dev.to/phimage/debugging-with-agents-a-lenvers-mcp-in-or-dap-out-5880</guid>
      <description>&lt;p&gt;Last month I built &lt;a href="https://phimage.github.io/blog/acpdbg-agent-in-lldb" rel="noopener noreferrer"&gt;&lt;strong&gt;acpdbg&lt;/strong&gt;&lt;/a&gt;: a debugger that hands&lt;br&gt;
its stopped state to a coding agent over ACP, so the agent can look at the crash&lt;br&gt;
and even drive lldb. I liked it. And while playing with an agent living inside the&lt;br&gt;
debugger, the obvious next thought showed up.&lt;/p&gt;

&lt;p&gt;I already have a Claude Code or a Copilot session open most of the day. So: &lt;strong&gt;why&lt;br&gt;
not have my debugging session expose a few MCP tools&lt;/strong&gt; — &lt;code&gt;bt&lt;/code&gt;, &lt;code&gt;frame variable&lt;/code&gt;,&lt;br&gt;
&lt;code&gt;p some_expr&lt;/code&gt;, &lt;code&gt;step&lt;/code&gt; — and let the agent I already have open just call them? The&lt;br&gt;
debug session becomes an MCP server; my chat agent picks up debugging superpowers.&lt;/p&gt;

&lt;p&gt;It's tempting. It's also, I think, backwards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thinking &lt;em&gt;à l'envers&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;À l'envers&lt;/em&gt; — "the wrong way round." Here's the tell. In acpdbg the &lt;strong&gt;debugger&lt;br&gt;
reaches out to the agent&lt;/strong&gt;: the debugger is the ACP client, it wakes the agent up&lt;br&gt;
when the program stops. The MCP-server idea keeps that same shape — &lt;em&gt;I&lt;/em&gt;, sitting&lt;br&gt;
at a stopped process, push tools up to whatever chat agent happens to be open.&lt;br&gt;
It's human-in-the-loop, and it's per-agent: I'd wire an MCP surface for Copilot,&lt;br&gt;
then again for Claude, then again for the next one.&lt;/p&gt;

&lt;p&gt;But an agent that debugs &lt;em&gt;autonomously&lt;/em&gt; doesn't want to be handed tools by me. It&lt;br&gt;
wants to &lt;strong&gt;reach into the debugger itself&lt;/strong&gt; — set a breakpoint, run to it, read a&lt;br&gt;
frame — on its own initiative. That's the arrow flipped: the &lt;strong&gt;agent&lt;/strong&gt; as the&lt;br&gt;
client, the debugger as the server it drives.&lt;/p&gt;

&lt;p&gt;And I don't need to invent a protocol for that. It exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  DAP already did the hard part
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://microsoft.github.io/debug-adapter-protocol/" rel="noopener noreferrer"&gt;&lt;strong&gt;Debug Adapter Protocol&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
is what VS Code and friends use to talk to &lt;em&gt;any&lt;/em&gt; debugger without knowing anything&lt;br&gt;
about it. Write one adapter per debugger, one client per editor, and they all&lt;br&gt;
interoperate — the same N×M collapse I liked about ACP for editors and MCP for&lt;br&gt;
tools, but pointed at debuggers.&lt;/p&gt;

&lt;p&gt;If the agent speaks DAP, it isn't tied to my open session or to one vendor's tool&lt;br&gt;
list. Every language with a debug adapter is suddenly reachable — LLDB for&lt;br&gt;
native code, Delve for Go, debugpy for Python — through one interface. The&lt;br&gt;
debugging capability lives in the agent, not in a bridge I re-bolt onto each chat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agents already speak it
&lt;/h2&gt;

&lt;p&gt;This isn't hypothetical. &lt;a href="https://github.com/can1357/oh-my-pi" rel="noopener noreferrer"&gt;&lt;strong&gt;oh my pi&lt;/strong&gt;&lt;/a&gt; (&lt;code&gt;omp&lt;/code&gt;,&lt;br&gt;
&lt;a href="https://omp.sh" rel="noopener noreferrer"&gt;omp.sh&lt;/a&gt;) is a terminal coding agent with &lt;strong&gt;native DAP support&lt;/strong&gt; —&lt;br&gt;
around twenty-seven operations — so it can attach to a real debugger, set&lt;br&gt;
breakpoints, pause, inspect frames, read locals, evaluate expressions and step,&lt;br&gt;
all on its own. For the usual suspects it works well.&lt;/p&gt;

&lt;p&gt;So I did the obvious thing: I pointed it at an &lt;em&gt;unusual&lt;/em&gt; language.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 4D try
&lt;/h2&gt;

&lt;p&gt;4D Server ships its own DAP server — it just listens on a fixed port (&lt;code&gt;19815&lt;/code&gt;),&lt;br&gt;
while omp likes to pick DAP ports dynamically. So the whole thing came down to a&lt;br&gt;
tiny (~120-line) TCP bridge: &lt;a href="https://github.com/mesopelagique/omp-4d-dap" rel="noopener noreferrer"&gt;&lt;strong&gt;omp-4d-dap&lt;/strong&gt;&lt;/a&gt;.&lt;br&gt;
Point omp at a port of its choosing, forward to 4D's, and the agent is talking DAP&lt;br&gt;
to a live 4D application.&lt;/p&gt;

&lt;p&gt;And it &lt;em&gt;works&lt;/em&gt;. With the bridge I got real live debugging of a running 4D app,&lt;br&gt;
driven by the agent: set breakpoints, step line by line, pull stack traces, and&lt;br&gt;
read state — the way you're supposed to on this platform — through &lt;code&gt;evaluate&lt;/code&gt; with&lt;br&gt;
&lt;code&gt;context:"watch"&lt;/code&gt;, which returns both the value and its 4D datatype.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2pw9b3k5njlj3gu7h5h5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2pw9b3k5njlj3gu7h5h5.png" alt="omp's Debug threads tool on a live 4D DAP session: adapter 4d, status running, listing the Remote Debugger Console and AdminWorker threads, with a stack-trace call in flight" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The agent's own &lt;code&gt;Debug threads&lt;/code&gt; call: adapter &lt;code&gt;4d&lt;/code&gt;, session running, real threads&lt;br&gt;
listed — then it goes for the stack trace. No editor, no me in the loop.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  …with honest gaps
&lt;/h2&gt;

&lt;p&gt;Not everything is there yet, and I keep a running list in the&lt;br&gt;
&lt;a href="https://github.com/mesopelagique/omp-4d-dap/blob/main/docs/4D-dap-supported-operations.md" rel="noopener noreferrer"&gt;supported-operations doc&lt;/a&gt;.&lt;br&gt;
The short version: scopes/variables time out (hence the &lt;code&gt;evaluate&lt;/code&gt;/watch detour),&lt;br&gt;
there's no pausing a running debuggee, 4D Server never emits a clean termination&lt;br&gt;
event (the client learns it's done by timing out), and the REPL runs code but&lt;br&gt;
hands back an empty result. You also have to set every breakpoint &lt;em&gt;before&lt;/em&gt; you let&lt;br&gt;
the code run. Live debugging, with caveats.&lt;/p&gt;

&lt;h2&gt;
  
  
  But most agents don't speak DAP — yet
&lt;/h2&gt;

&lt;p&gt;Here's the catch that brings my "backwards" idea back from the dead: &lt;strong&gt;omp has DAP&lt;br&gt;
inside. Claude Code and Copilot don't.&lt;/strong&gt; So the clean, universal path only works&lt;br&gt;
today for the handful of agents that ship a DAP client.&lt;/p&gt;

&lt;p&gt;For everyone else, the pragmatic bridge is exactly the thing I called &lt;em&gt;à l'envers&lt;/em&gt;&lt;br&gt;
— you meet the agent where it already is. Two ways to do that right now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Documented skills&lt;/strong&gt; — teach the agent &lt;em&gt;how&lt;/em&gt; to debug in prose: the commands,
the workflow, the platform's quirks (on 4D: set breakpoints first, read state
through &lt;code&gt;evaluate&lt;/code&gt;/watch). The agent runs a debugger through the shell it
already has.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An MCP debug server&lt;/strong&gt; — expose &lt;code&gt;set_breakpoint&lt;/code&gt;, &lt;code&gt;step&lt;/code&gt;, &lt;code&gt;evaluate&lt;/code&gt;,
&lt;code&gt;backtrace&lt;/code&gt; as MCP tools, and any MCP-speaking agent picks them up. Which, yes,
is my original idea — only now framed as &lt;em&gt;the fallback for DAP-less agents&lt;/em&gt;
rather than the main event.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So it's not one arrow or the other. It's: DAP when the agent has it, MCP or skills&lt;br&gt;
to bridge the ones that don't — ideally over the &lt;em&gt;same&lt;/em&gt; debug backend underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  So which way round?
&lt;/h2&gt;

&lt;p&gt;I lean toward DAP for anything autonomous: an agent that has it shouldn't wait for&lt;br&gt;
me to hand it a debugger. But most of the agents I actually use don't have it yet,&lt;br&gt;
so the MCP-tools-and-skills bridge is what gets Claude Code or Copilot debugging&lt;br&gt;
today. And I'm not throwing acpdbg away either — when &lt;em&gt;I'm&lt;/em&gt; at the crash, the&lt;br&gt;
debugger-drives-the-agent loop still feels right. It's a try, in every direction.&lt;/p&gt;

&lt;p&gt;Bridge and caveats: &lt;a href="https://github.com/mesopelagique/omp-4d-dap" rel="noopener noreferrer"&gt;github.com/mesopelagique/omp-4d-dap&lt;/a&gt;.&lt;br&gt;
Tell me which way round you'd build it. 🐛&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>dap</category>
      <category>mcp</category>
    </item>
    <item>
      <title>acpdbg: let the agent sit at the debugger 🐛</title>
      <dc:creator>Eric Marchand</dc:creator>
      <pubDate>Sat, 11 Jul 2026 11:08:35 +0000</pubDate>
      <link>https://dev.to/phimage/acpdbg-let-the-agent-sit-at-the-debugger-47co</link>
      <guid>https://dev.to/phimage/acpdbg-let-the-agent-sit-at-the-debugger-47co</guid>
      <description>&lt;p&gt;I had an idea, and it starts from a habit.&lt;/p&gt;

&lt;p&gt;LLM agents are genuinely good at &lt;strong&gt;static analysis&lt;/strong&gt;: give them a backtrace and&lt;br&gt;
the source around it, and they usually spot the bad pointer before I do. So what&lt;br&gt;
do I actually do when a native program crashes? I copy the stack trace from the&lt;br&gt;
debugger, paste it into the agent's context, then copy the source of the&lt;br&gt;
functions involved, paste again… I'm the transport layer between two programs&lt;br&gt;
that both live on my machine.&lt;/p&gt;

&lt;p&gt;That's the idea: &lt;strong&gt;why not let the agent look at the lldb debug data itself —&lt;br&gt;
and even control the debugging?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I already wrote about &lt;a href="https://phimage.github.io/blog/acp-copilot-xcode" rel="noopener noreferrer"&gt;ACP, the Agent Client Protocol&lt;/a&gt; —&lt;br&gt;
the standard that lets any agent talk to any client. Usually the client is an&lt;br&gt;
editor. But nothing says it has to be. A debugger is a perfectly good ACP client&lt;br&gt;
too. So I built one.&lt;/p&gt;
&lt;h2&gt;
  
  
  acpdbg
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/phimage/acpdbg" rel="noopener noreferrer"&gt;&lt;strong&gt;acpdbg&lt;/strong&gt;&lt;/a&gt; is an LLDB assistant. When your&lt;br&gt;
C/C++/Rust/Swift program stops — crash, signal, or breakpoint — it captures an&lt;br&gt;
enriched snapshot (backtrace, every frame's live arguments, surrounding source)&lt;br&gt;
and hands it to your coding agent over ACP: GitHub Copilot CLI, Gemini CLI, or&lt;br&gt;
Claude Code through its ACP adapter.&lt;/p&gt;

&lt;p&gt;The part I like most: the agent doesn't just read a frozen report. Through a&lt;br&gt;
small MCP tool bridge it can run &lt;em&gt;live&lt;/em&gt; debugger commands against the stopped&lt;br&gt;
process — &lt;code&gt;bt&lt;/code&gt;, &lt;code&gt;frame variable&lt;/code&gt;, &lt;code&gt;p some_expr&lt;/code&gt; — to confirm its hypothesis&lt;br&gt;
instead of guessing. And with the opt-in &lt;strong&gt;control mode&lt;/strong&gt;, it gets &lt;code&gt;step_over&lt;/code&gt;,&lt;br&gt;
&lt;code&gt;continue_execution&lt;/code&gt;, &lt;code&gt;set_breakpoint&lt;/code&gt;… so it can debug like a human would:&lt;br&gt;
set a breakpoint, run to it, step, watch the state evolve.&lt;/p&gt;
&lt;h2&gt;
  
  
  Try it fast
&lt;/h2&gt;

&lt;p&gt;The whole loop works offline with a bundled mock agent, nothing else to install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;acpdbg
git clone https://github.com/phimage/acpdbg &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;acpdbg/samples
make                &lt;span class="c"&gt;# builds ./crash with -g&lt;/span&gt;
acpdbg &lt;span class="nt"&gt;--&lt;/span&gt; ./crash   &lt;span class="c"&gt;# runs it; on the crash the agent explains&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swap in a real agent for real analysis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;acpdbg &lt;span class="nt"&gt;--agent&lt;/span&gt; copilot &lt;span class="nt"&gt;--&lt;/span&gt; ./crash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Real output from that command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;acpdbg → copilot (investigating…)

Confirmed live: `s` is 0x0000000000000000 — a NULL pointer — right where
strlen(s) dereferences it.

Root cause: in main, `name` is NULL when the program runs with no arguments,
and describe() hands it to strlen() with no check.

One-line fix: return s ? strlen(s) : 0;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Inside lldb — and inside Xcode
&lt;/h2&gt;

&lt;p&gt;It's also a plain LLDB plugin. Install it once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;acpdbg &lt;span class="nt"&gt;--install-lldbinit&lt;/span&gt; &lt;span class="nt"&gt;--agent&lt;/span&gt; copilot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and every lldb session — including &lt;strong&gt;Xcode's debugger console&lt;/strong&gt; — gets new&lt;br&gt;
commands. Stop anywhere (a crash, a breakpoint, a watchpoint) and just type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(lldb) ask why is `retry_count` already 3 here?
(lldb) copilot in one sentence, why did this stop?
(lldb) claude what would you change to fix it?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each installed agent gets its own command, so you can get a second opinion from&lt;br&gt;
another model without touching the config.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's a try
&lt;/h2&gt;

&lt;p&gt;I don't claim this is &lt;em&gt;the&lt;/em&gt; way to debug. It's an experiment: the interesting&lt;br&gt;
part for me is that ACP made it cheap to build — I wrote a client once, and&lt;br&gt;
every ACP-speaking agent works with it, today's and tomorrow's. The same&lt;br&gt;
N×M collapse I liked about the protocol in editors, applied to a debugger.&lt;/p&gt;

&lt;p&gt;Code, docs, and caveats: &lt;a href="https://github.com/phimage/acpdbg" rel="noopener noreferrer"&gt;github.com/phimage/acpdbg&lt;/a&gt;.&lt;br&gt;
Tell me where it breaks. 🐛&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>acp</category>
      <category>lldb</category>
    </item>
    <item>
      <title>Pipeline, Flow, or Chain? Picking the Right Tool to Wire LLM Calls Together</title>
      <dc:creator>Eric Marchand</dc:creator>
      <pubDate>Sat, 11 Jul 2026 09:44:51 +0000</pubDate>
      <link>https://dev.to/phimage/pipeline-flow-or-chain-picking-the-right-tool-to-wire-llm-calls-together-46k5</link>
      <guid>https://dev.to/phimage/pipeline-flow-or-chain-picking-the-right-tool-to-wire-llm-calls-together-46k5</guid>
      <description>&lt;p&gt;In the &lt;a href="https://phimage.github.io/blog/agents-as-planners/" rel="noopener noreferrer"&gt;previous post&lt;/a&gt; I argued that agents are great&lt;br&gt;
&lt;em&gt;planners&lt;/em&gt; and DAGs are great &lt;em&gt;executors&lt;/em&gt;. This one is the practical follow-up: when&lt;br&gt;
you actually sit down to wire several LLM calls together, &lt;strong&gt;what tool do you reach&lt;br&gt;
for?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because the moment one prompt's output feeds the next, you've built a workflow —&lt;br&gt;
whether you call it that or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;download transcript → summarize → translate
       (tool)          (LLM)       (LLM)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That tiny pipeline is already the whole problem in miniature: a non-LLM step (fetch a&lt;br&gt;
YouTube transcript), then a model call, then another model call that depends on the&lt;br&gt;
first. Run it as one giant prompt and you lose visibility; split it into steps and you&lt;br&gt;
gain debuggability — at the cost of more calls and more state to manage.&lt;/p&gt;
&lt;h2&gt;
  
  
  The naming trap
&lt;/h2&gt;

&lt;p&gt;Half the confusion is vocabulary. The same idea ships under a dozen labels:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;What it whispers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Chain&lt;/td&gt;
&lt;td&gt;sequential, output → input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipeline&lt;/td&gt;
&lt;td&gt;stages, data flowing through&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flow&lt;/td&gt;
&lt;td&gt;branches and conditions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow&lt;/td&gt;
&lt;td&gt;general orchestration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent workflow&lt;/td&gt;
&lt;td&gt;the model also &lt;em&gt;decides&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The word sets expectations. "Chain" promises a straight line; "agent workflow"&lt;br&gt;
promises the thing might re-plan on you mid-run. Pick the label that matches how much&lt;br&gt;
autonomy you're actually handing over — calling a deterministic two-step pipeline an&lt;br&gt;
"agent" only invites disappointment.&lt;/p&gt;
&lt;h2&gt;
  
  
  The real choice: library or orchestrator?
&lt;/h2&gt;

&lt;p&gt;There are two families of tools, and they solve different problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LLM-native chaining libraries&lt;/strong&gt; — &lt;a href="https://www.langchain.com/" rel="noopener noreferrer"&gt;LangChain&lt;/a&gt;,&lt;br&gt;
&lt;a href="https://docs.llamaindex.ai/en/stable/module_guides/workflow/" rel="noopener noreferrer"&gt;LlamaIndex Workflows&lt;/a&gt;,&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/azure/machine-learning/prompt-flow/" rel="noopener noreferrer"&gt;Azure Prompt Flow&lt;/a&gt;,&lt;br&gt;
or visual layers like &lt;a href="https://flowiseai.com/" rel="noopener noreferrer"&gt;Flowise&lt;/a&gt;. These understand&lt;br&gt;
&lt;em&gt;LLM-specific&lt;/em&gt; concerns out of the box: prompt templating, passing context between&lt;br&gt;
steps, token budgets, streaming, retries on a flaky model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;General orchestrators&lt;/strong&gt; — &lt;a href="https://airflow.apache.org/" rel="noopener noreferrer"&gt;Airflow&lt;/a&gt;,&lt;br&gt;
&lt;a href="https://www.prefect.io/" rel="noopener noreferrer"&gt;Prefect&lt;/a&gt;, &lt;a href="https://aws.amazon.com/step-functions/" rel="noopener noreferrer"&gt;AWS Step Functions&lt;/a&gt;,&lt;br&gt;
&lt;a href="https://azure.microsoft.com/en-us/products/logic-apps" rel="noopener noreferrer"&gt;Azure Logic Apps&lt;/a&gt;. These treat&lt;br&gt;
each LLM call as just another task in a DAG, and give you the heavyweight reliability&lt;br&gt;
machinery: durable state, scheduling, checkpointing, audit trails, human approval.&lt;/p&gt;

&lt;p&gt;The rule of thumb that falls out of the last post:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Few prompts, mostly LLM glue   → chaining library
Many steps, must not fail      → orchestrator (LLM call = one task)
The model decides the path     → agent, with one of the above underneath
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When you don't need either
&lt;/h2&gt;

&lt;p&gt;Don't reach for a framework reflexively. If the task is genuinely simple, &lt;strong&gt;one&lt;br&gt;
well-crafted prompt&lt;/strong&gt; (few-shot or chain-of-thought) often beats a three-step pipeline&lt;br&gt;
— fewer calls, less latency, nothing to orchestrate. Chaining earns its keep when&lt;br&gt;
subtasks are distinct enough that isolating them actually improves accuracy and lets&lt;br&gt;
you debug each one independently. The cost is real: every extra hop adds latency, and a&lt;br&gt;
weak early step poisons everything downstream.&lt;/p&gt;
&lt;h2&gt;
  
  
  A concrete chain
&lt;/h2&gt;

&lt;p&gt;To get a feel for the moving parts I built &lt;a href="https://github.com/mesopelagique/PromptKit" rel="noopener noreferrer"&gt;PromptKit&lt;/a&gt;,&lt;br&gt;
a small 4D toolkit where a chain is just named prompts piped together — the YouTube&lt;br&gt;
example above, minus the download step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var $result:=$runner.newChain().prompt("summarize").prompt("translate").run($transcript)

// $result.text     -&amp;gt; final translated summary
// $result.outputs  -&amp;gt; each step's output, for inspection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing exotic — but writing it made the trade-offs tangible: where state lives, what&lt;br&gt;
happens when step two fails, how you'd add a branch. Which is really the point. You&lt;br&gt;
don't pick the tool by reading the marketing; you pick it by knowing whether your&lt;br&gt;
problem is &lt;em&gt;LLM glue&lt;/em&gt; or &lt;em&gt;reliable execution&lt;/em&gt; — and most of the time, it's a bit of&lt;br&gt;
both.&lt;/p&gt;




&lt;p&gt;My take: "chain vs. workflow vs. agent" is less an architecture question than an&lt;br&gt;
honesty question — how deterministic is your process, really? Name it accordingly,&lt;br&gt;
then pick the lightest tool that survives the day you actually need a retry.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>workflow</category>
      <category>orchestration</category>
    </item>
    <item>
      <title>When Agents Become Planners, What Remains of Workflow Orchestration?</title>
      <dc:creator>Eric Marchand</dc:creator>
      <pubDate>Sat, 11 Jul 2026 09:44:44 +0000</pubDate>
      <link>https://dev.to/phimage/when-agents-become-planners-what-remains-of-workflow-orchestration-50an</link>
      <guid>https://dev.to/phimage/when-agents-become-planners-what-remains-of-workflow-orchestration-50an</guid>
      <description>&lt;p&gt;For years, software automation has been built around a simple idea: define the&lt;br&gt;
process, then execute it. Whether using a script, a workflow engine, or a DAG, the&lt;br&gt;
principle is always the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A → B → C → D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The developer knows the steps in advance.&lt;/p&gt;

&lt;p&gt;AI agents challenge this model. Instead of defining &lt;em&gt;how&lt;/em&gt; to achieve a goal, we&lt;br&gt;
increasingly define &lt;em&gt;what&lt;/em&gt; we want and let the agent figure out the steps.&lt;/p&gt;

&lt;p&gt;This reminds me of the difference between traditional programming and agentic&lt;br&gt;
programming.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Traditional Programming&lt;/th&gt;
&lt;th&gt;Agentic Programming&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Define the algorithm&lt;/td&gt;
&lt;td&gt;Define the objective&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deterministic execution&lt;/td&gt;
&lt;td&gt;Probabilistic execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Every path is known&lt;/td&gt;
&lt;td&gt;Paths emerge dynamically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optimized for reliability&lt;/td&gt;
&lt;td&gt;Optimized for adaptability&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When the process is well known, code is often the best solution. When the process is&lt;br&gt;
uncertain, constantly changing, or requires exploration, agents start to shine.&lt;/p&gt;

&lt;p&gt;A useful way to think about it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Known problem    → Code
Known process    → Workflow
Unknown process  → Agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is why some people argue that traditional orchestrators such as&lt;br&gt;
&lt;a href="https://airflow.apache.org/" rel="noopener noreferrer"&gt;Apache Airflow&lt;/a&gt; or&lt;br&gt;
&lt;a href="https://aws.amazon.com/step-functions/" rel="noopener noreferrer"&gt;AWS Step Functions&lt;/a&gt; are not well suited for&lt;br&gt;
agentic systems. AI agents are fundamentally non-deterministic. They may decide to use&lt;br&gt;
different tools, follow different paths, or even change their plan while executing it.&lt;/p&gt;

&lt;p&gt;A static DAG cannot describe every possible future path.&lt;/p&gt;

&lt;p&gt;But does that mean workflow orchestration is becoming obsolete?&lt;/p&gt;

&lt;p&gt;I don't think so.&lt;/p&gt;

&lt;p&gt;Even the most advanced agents still need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State persistence&lt;/li&gt;
&lt;li&gt;Retries&lt;/li&gt;
&lt;li&gt;Checkpointing&lt;/li&gt;
&lt;li&gt;Human approval&lt;/li&gt;
&lt;li&gt;Scheduling&lt;/li&gt;
&lt;li&gt;Audit trails&lt;/li&gt;
&lt;li&gt;Observability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, they still need many of the things workflow engines have solved for&lt;br&gt;
years.&lt;/p&gt;

&lt;p&gt;The architecture is simply evolving.&lt;/p&gt;

&lt;p&gt;Yesterday we had:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Workflow Engine
       ↓
      Tasks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tomorrow we may have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent
  ↓
Execution Engine
  ↓
Tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent becomes responsible for planning. The orchestration layer becomes&lt;br&gt;
responsible for reliable execution.&lt;/p&gt;

&lt;p&gt;This is why I don't believe DAGs are disappearing. They are simply moving down a layer.&lt;/p&gt;

&lt;p&gt;The mistake is thinking agents eliminate workflows. What they really eliminate is the&lt;br&gt;
need to define every workflow in advance.&lt;/p&gt;

&lt;p&gt;Agents are excellent planners. Workflows are excellent executors.&lt;/p&gt;

&lt;p&gt;The future may not be &lt;em&gt;Agents vs DAGs&lt;/em&gt;. It may simply be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Agents for planning. DAGs for execution.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Worth reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/topuzas/advanced-langgraph-orchestration-enterprise-ready-ai-workflow-management-186"&gt;Advanced LangGraph Orchestration — Enterprise-Ready AI Workflow Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://intuitionlabs.ai/articles/agentic-ai-temporal-orchestration" rel="noopener noreferrer"&gt;Agentic AI and Temporal Orchestration&lt;/a&gt; — pairing agents with &lt;a href="https://temporal.io/" rel="noopener noreferrer"&gt;Temporal&lt;/a&gt; for durable execution&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://airflow.apache.org/" rel="noopener noreferrer"&gt;Apache Airflow&lt;/a&gt; · &lt;a href="https://aws.amazon.com/step-functions/" rel="noopener noreferrer"&gt;AWS Step Functions&lt;/a&gt; — the classic DAG-based orchestrators&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2605.13848" rel="noopener noreferrer"&gt;GraphBit: A Graph-based Agentic Framework for Non-Linear Agent Orchestration&lt;/a&gt; — agents and graphs, together&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2606.09692" rel="noopener noreferrer"&gt;Observability for Delegated Execution in Agentic AI Systems&lt;/a&gt; — the execution-layer concerns that don't go away&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;As a side project, and to better understand what happens inside a workflow engine, I'm&lt;br&gt;
also experimenting with implementing a DAG engine in 4D. It started as a task scheduler&lt;br&gt;
but evolved into a good opportunity to explore orchestration concepts from the inside.&lt;/p&gt;

&lt;p&gt;The project is available here:&lt;br&gt;
&lt;a href="https://github.com/mesopelagique/Scheduler/blob/main/Documentation/Classes/Dag.md" rel="noopener noreferrer"&gt;mesopelagique/Scheduler — Dag.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A quick word on where I'm coming from: my hands-on experience with DAGs proper is&lt;br&gt;
limited to &lt;a href="https://airflow.apache.org/" rel="noopener noreferrer"&gt;Airflow&lt;/a&gt; for ML pipelines — pulling data from&lt;br&gt;
the data warehouse, cleaning it, transforming it, and feeding the next stage. Beyond&lt;br&gt;
that, as a developer I mostly live in CI tooling —&lt;br&gt;
&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;,&lt;br&gt;
&lt;a href="https://docs.gitlab.com/ee/ci/" rel="noopener noreferrer"&gt;GitLab CI&lt;/a&gt;,&lt;br&gt;
&lt;a href="https://www.jetbrains.com/teamcity/" rel="noopener noreferrer"&gt;TeamCity&lt;/a&gt; — which share a lot of common ground&lt;br&gt;
with workflow engines: stages and dependencies, retries, caching/artifacts,&lt;br&gt;
conditional steps, and approvals. Different vocabulary, same orchestration instincts.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>workflow</category>
      <category>orchestration</category>
    </item>
    <item>
      <title>macOS 27's AI dev ecosystem — and pointing 4D AIKit at a local model 🍎</title>
      <dc:creator>Eric Marchand</dc:creator>
      <pubDate>Sat, 11 Jul 2026 09:44:36 +0000</pubDate>
      <link>https://dev.to/phimage/macos-27s-ai-dev-ecosystem-and-pointing-4d-aikit-at-a-local-model-1d92</link>
      <guid>https://dev.to/phimage/macos-27s-ai-dev-ecosystem-and-pointing-4d-aikit-at-a-local-model-1d92</guid>
      <description>&lt;p&gt;For a year, Apple's on-device model was walled off — reachable only from Swift,&lt;br&gt;
only inside an app you built in Xcode. &lt;strong&gt;macOS 27 tears that wall down.&lt;/strong&gt; The same&lt;br&gt;
Foundation Models are now scriptable from the terminal and from Python, and there's&lt;br&gt;
a real framework story forming around them. Three pieces worth your attention.&lt;/p&gt;
&lt;h2&gt;
  
  
  Two models: System and PCC
&lt;/h2&gt;

&lt;p&gt;There's now a hybrid setup with two tiers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;system&lt;/code&gt;&lt;/strong&gt; — the on-device Apple Foundation Model. Default, free, fully private,
nothing leaves the Mac.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;pcc&lt;/code&gt;&lt;/strong&gt; — a larger model on &lt;strong&gt;Private Cloud Compute&lt;/strong&gt;. More capable, but subject
to daily usage limits (higher caps come with paid iCloud+ tiers).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You pick per call, so the cheap private one is the default and you reach for PCC&lt;br&gt;
only when a task needs the extra horsepower.&lt;/p&gt;
&lt;h2&gt;
  
  
  The &lt;code&gt;fm&lt;/code&gt; CLI
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;fm&lt;/code&gt; comes &lt;strong&gt;pre-installed with macOS 27&lt;/strong&gt; — no install, just update and type &lt;code&gt;fm&lt;/code&gt;.&lt;br&gt;
It's built for scripting and automation, not just chatting:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftvclcxu2hzh4j6219rbs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftvclcxu2hzh4j6219rbs.png" alt="The fm CLI: usage, commands, models, and  raw `fm serve` endraw  running an OpenAI-compatible endpoint" width="800" height="898"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The commands cover the obvious ground — one-shot generation, interactive chat,&lt;br&gt;
token counting, JSON schema generation, plus availability and quota checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;fm respond &lt;span class="s1"&gt;'What is Swift?'&lt;/span&gt;
fm respond &lt;span class="nt"&gt;--model&lt;/span&gt; pcc &lt;span class="nt"&gt;--stream&lt;/span&gt; &lt;span class="s1"&gt;'Summarize this article'&lt;/span&gt;
fm chat &lt;span class="nt"&gt;--instructions&lt;/span&gt; &lt;span class="s1"&gt;'You are a coding assistant'&lt;/span&gt;
fm token-count &lt;span class="s1"&gt;'Hello world'&lt;/span&gt;
fm schema object &lt;span class="nt"&gt;--name&lt;/span&gt; Person &lt;span class="nt"&gt;--string&lt;/span&gt; name &lt;span class="nt"&gt;--int&lt;/span&gt; age
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The part that matters: &lt;code&gt;fm serve&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Here's the one most WWDC recaps skipped. &lt;code&gt;fm serve&lt;/code&gt; starts an&lt;br&gt;
&lt;strong&gt;OpenAI-compatible Chat Completions server&lt;/strong&gt;, loopback-only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;url&lt;/span&gt;     &lt;span class="n"&gt;http&lt;/span&gt;://&lt;span class="m"&gt;127&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="m"&gt;1976&lt;/span&gt;
&lt;span class="n"&gt;access&lt;/span&gt;  &lt;span class="n"&gt;loopback&lt;/span&gt;-&lt;span class="n"&gt;only&lt;/span&gt;

  · &lt;span class="n"&gt;POST&lt;/span&gt; /&lt;span class="n"&gt;v1&lt;/span&gt;/&lt;span class="n"&gt;chat&lt;/span&gt;/&lt;span class="n"&gt;completions&lt;/span&gt;
  · &lt;span class="n"&gt;GET&lt;/span&gt;  /&lt;span class="n"&gt;v1&lt;/span&gt;/&lt;span class="n"&gt;models&lt;/span&gt;
  · &lt;span class="n"&gt;GET&lt;/span&gt;  /&lt;span class="n"&gt;health&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OpenAI-compatible is the magic word. It speaks the same &lt;code&gt;/v1/chat/completions&lt;/code&gt; dialect&lt;br&gt;
as every other provider, so &lt;strong&gt;any software or library that already talks to an&lt;br&gt;
OpenAI-style API can point straight at it&lt;/strong&gt; — your existing client, SDK, agent&lt;br&gt;
framework, or tool, unchanged beyond swapping the base URL to&lt;br&gt;
&lt;code&gt;http://127.0.0.1:1976/v1&lt;/code&gt;. Whatever you've already wired up for OpenAI now drives an&lt;br&gt;
Apple Foundation Model (on-device or PCC), with no API key and no cloud bill.&lt;/p&gt;

&lt;p&gt;For me that lands on &lt;a href="https://github.com/4d/4D-AIKit" rel="noopener noreferrer"&gt;4D AIKit&lt;/a&gt;: point its base URL at&lt;br&gt;
the local server and the same 4D code I'd aim at a remote provider runs against a local&lt;br&gt;
model, no new component. But the point is general — anything OpenAI-compatible gets a&lt;br&gt;
free local backend. That's a genuinely useful default for prototyping, and for anything&lt;br&gt;
privacy-sensitive, maybe the production default too.&lt;/p&gt;

&lt;p&gt;For the Python crowd, there's also an official&lt;br&gt;
&lt;a href="https://github.com/apple/python-apple-fm-sdk" rel="noopener noreferrer"&gt;Foundation Models SDK for Python&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core AI + a maturing Foundation Models framework
&lt;/h2&gt;

&lt;p&gt;Alongside the CLI, Apple shipped &lt;a href="https://developer.apple.com/documentation/coreai/" rel="noopener noreferrer"&gt;&lt;strong&gt;Core AI&lt;/strong&gt;&lt;/a&gt; —&lt;br&gt;
a framework for running AI models directly in your app on Apple silicon — and a&lt;br&gt;
solid round of upgrades to&lt;br&gt;
&lt;a href="https://developer.apple.com/documentation/FoundationModels" rel="noopener noreferrer"&gt;&lt;strong&gt;Foundation Models&lt;/strong&gt;&lt;/a&gt;.&lt;br&gt;
The framework now has the pieces that were missing: tool calling, context and&lt;br&gt;
conversation history, multimodal input (images, vision), and server-model access&lt;br&gt;
behind the same Swift API. It's starting to look like something you'd actually&lt;br&gt;
ship on, not just demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worth reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/videos/play/wwdc2026/334/" rel="noopener noreferrer"&gt;Build AI-powered scripts with the fm CLI and Python SDK — WWDC26 session 334&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/documentation/coreai/" rel="noopener noreferrer"&gt;Core AI — Apple Developer Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/documentation/FoundationModels" rel="noopener noreferrer"&gt;Foundation Models framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/apple/python-apple-fm-sdk" rel="noopener noreferrer"&gt;python-apple-fm-sdk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The pattern, again: a model that used to be locked inside one language and one app&lt;br&gt;
becomes a local server speaking a standard dialect — and the moment it does, every&lt;br&gt;
tool that already speaks that dialect (AIKit included) gets it for free. 🍎&lt;/p&gt;




&lt;h2&gt;
  
  
  EDIT — wait, I had &lt;code&gt;fm&lt;/code&gt; first 😅
&lt;/h2&gt;

&lt;p&gt;Funny postscript: I'd already built my own &lt;code&gt;fm&lt;/code&gt;. Back when I wrote the&lt;br&gt;
&lt;a href="https://phimage.github.io/blog/apple-foundation-models/" rel="noopener noreferrer"&gt;Apple Foundation Models post&lt;/a&gt; (mid-2025), I made a&lt;br&gt;
little command-line tool — &lt;a href="https://github.com/phimage/FoundationModelCli/" rel="noopener noreferrer"&gt;&lt;code&gt;phimage/FoundationModelCli&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
— specifically so I could type &lt;code&gt;fm&lt;/code&gt; and poke at Foundation Models from the terminal.&lt;br&gt;
A year later Apple shipped a CLI with the &lt;em&gt;exact same name&lt;/em&gt;. No collision, no hard&lt;br&gt;
feelings… but for the record, I was running &lt;code&gt;fm&lt;/code&gt; first. 🙂&lt;/p&gt;

</description>
      <category>ai</category>
      <category>apple</category>
      <category>foundationmodels</category>
      <category>4d</category>
    </item>
    <item>
      <title>ACP: Copilot in Xcode, without the plugin 🔌</title>
      <dc:creator>Eric Marchand</dc:creator>
      <pubDate>Sat, 11 Jul 2026 09:44:24 +0000</pubDate>
      <link>https://dev.to/phimage/acp-copilot-in-xcode-without-the-plugin-mog</link>
      <guid>https://dev.to/phimage/acp-copilot-in-xcode-without-the-plugin-mog</guid>
      <description>&lt;p&gt;There's a new standardization layer in the agentic-coding stack, and it's a good&lt;br&gt;
one: the &lt;strong&gt;Agent Client Protocol (ACP)&lt;/strong&gt;. After MCP standardized &lt;em&gt;what tools an&lt;br&gt;
agent can reach&lt;/em&gt;, ACP standardizes &lt;em&gt;how editors and agents talk to each other&lt;/em&gt; —&lt;br&gt;
local or remote — so any ACP agent drops into any ACP editor with no bespoke,&lt;br&gt;
per-vendor glue. It's developed in the open (JetBrains and Zed), and there's a&lt;br&gt;
clean &lt;a href="https://agentclientprotocol.com/get-started/introduction" rel="noopener noreferrer"&gt;introduction&lt;/a&gt; if&lt;br&gt;
you want the protocol view.&lt;/p&gt;

&lt;p&gt;The reason this matters today: &lt;strong&gt;Xcode 27 speaks ACP.&lt;/strong&gt; (It's in the developer&lt;br&gt;
beta, and it's already turning up in the&lt;br&gt;
&lt;a href="https://www.reddit.com/r/Xcode/comments/1u203ho/use_any_llm_in_xcode_27_via_acp/" rel="noopener noreferrer"&gt;26.6 RC&lt;/a&gt;.)&lt;/p&gt;
&lt;h2&gt;
  
  
  MCP vs ACP, in one line
&lt;/h2&gt;

&lt;p&gt;Xcode 27 actually has two protocol layers, and it's worth keeping them straight:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MCP&lt;/strong&gt; decides &lt;em&gt;what&lt;/em&gt; an agent can do inside Xcode — read files, build, run
tests, pull diagnostics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ACP&lt;/strong&gt; decides &lt;em&gt;which&lt;/em&gt; agents are even allowed to connect in the first place.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So ACP is the front door, MCP is the toolbox once you're inside. Apple shipped&lt;br&gt;
GitHub and Figma as launch plugin partners — but because the door is a &lt;em&gt;standard&lt;/em&gt;,&lt;br&gt;
you don't actually need their plugin. Any ACP-speaking agent can knock.&lt;/p&gt;
&lt;h2&gt;
  
  
  The trick: register Copilot CLI as a raw ACP agent
&lt;/h2&gt;

&lt;p&gt;Copilot CLI can run as an ACP server, so you can wire it straight into Xcode&lt;br&gt;
instead of installing the official plugin. In &lt;strong&gt;Xcode → Settings → Intelligence →&lt;br&gt;
Coding Intelligence → Add an Agent…&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo4i6ehlnu77vyny0dpxp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo4i6ehlnu77vyny0dpxp.png" alt="Xcode's " width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;Copilot&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Executable:&lt;/strong&gt; &lt;code&gt;/opt/homebrew/bin/copilot&lt;/code&gt; (wherever Homebrew put it — &lt;code&gt;which copilot&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arguments:&lt;/strong&gt; &lt;code&gt;--acp&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the whole registration. Xcode notes that ACP agents get full use of Xcode&lt;br&gt;
and your project context, and it asks for consent before a new agent connects —&lt;br&gt;
the protocol is permissioned by design, not a backdoor.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pick your model with an env var
&lt;/h2&gt;

&lt;p&gt;The fun part: you're not locked to one model. Add an &lt;strong&gt;Environment Variable&lt;/strong&gt; to&lt;br&gt;
the agent and pin whichever model you want — for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;COPILOT_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;claude-sonnet-4.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So you get Copilot's harness and auth, driving the model of your choice, inside&lt;br&gt;
Apple's IDE. "Use any LLM in Xcode" is barely an exaggeration.&lt;/p&gt;
&lt;h2&gt;
  
  
  Under the hood
&lt;/h2&gt;

&lt;p&gt;If you want to see what Xcode is launching, the CLI flag is documented. &lt;code&gt;--acp&lt;/code&gt;&lt;br&gt;
defaults to &lt;strong&gt;stdio&lt;/strong&gt; mode (ideal for an IDE spawning the process); add &lt;code&gt;--port&lt;/code&gt;&lt;br&gt;
for TCP instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;copilot &lt;span class="nt"&gt;--acp&lt;/span&gt; &lt;span class="nt"&gt;--stdio&lt;/span&gt;      &lt;span class="c"&gt;# stdio (default when --acp is passed)&lt;/span&gt;
copilot &lt;span class="nt"&gt;--acp&lt;/span&gt; &lt;span class="nt"&gt;--port&lt;/span&gt; 3000  &lt;span class="c"&gt;# TCP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One caveat worth flagging: ACP support in Copilot CLI is still &lt;strong&gt;public preview&lt;/strong&gt;,&lt;br&gt;
so flags and behavior may shift. Tool-filtering and reasoning-effort flags, if you&lt;br&gt;
pass them, apply per session started by the client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worth reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://agentclientprotocol.com/get-started/introduction" rel="noopener noreferrer"&gt;Agent Client Protocol — introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://agentclientprotocol.com/get-started/agents" rel="noopener noreferrer"&gt;Agents that speak ACP&lt;/a&gt; · &lt;a href="https://agentclientprotocol.com/get-started/clients" rel="noopener noreferrer"&gt;Clients that speak ACP&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/copilot/reference/copilot-cli-reference/acp-server" rel="noopener noreferrer"&gt;Copilot CLI ACP server — GitHub Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.reddit.com/r/Xcode/comments/1u203ho/use_any_llm_in_xcode_27_via_acp/" rel="noopener noreferrer"&gt;Use any LLM in Xcode 27 via ACP&lt;/a&gt; (Reddit)&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The bigger picture: the N×M integration problem — every editor needing a custom&lt;br&gt;
connector for every agent — collapses to N+M once both sides speak a shared&lt;br&gt;
protocol. MCP did it for tools; ACP is doing it for the agents themselves. Xcode&lt;br&gt;
adopting it this fast is the surprise. 🔌&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>xcode</category>
      <category>acp</category>
    </item>
  </channel>
</rss>
